git://ftp.safe.ca
/
safe
/
jmp
/
linux-2.6
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
FS-Cache: Fix lock misorder in fscache_write_op()
[safe/jmp/linux-2.6]
/
drivers
/
scsi
/
scsi_error.c
diff --git
a/drivers/scsi/scsi_error.c
b/drivers/scsi/scsi_error.c
index
ad019ec
..
1b0060b
100644
(file)
--- a/
drivers/scsi/scsi_error.c
+++ b/
drivers/scsi/scsi_error.c
@@
-124,33
+124,22
@@
int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
enum blk_eh_timer_return scsi_times_out(struct request *req)
{
struct scsi_cmnd *scmd = req->special;
enum blk_eh_timer_return scsi_times_out(struct request *req)
{
struct scsi_cmnd *scmd = req->special;
- enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
scsi_log_completion(scmd, TIMEOUT_ERROR);
if (scmd->device->host->transportt->eh_timed_out)
enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
scsi_log_completion(scmd, TIMEOUT_ERROR);
if (scmd->device->host->transportt->eh_timed_out)
-
eh_timed_out = scmd->device->host->transportt->eh_timed_out
;
+
rtn = scmd->device->host->transportt->eh_timed_out(scmd)
;
else if (scmd->device->host->hostt->eh_timed_out)
else if (scmd->device->host->hostt->eh_timed_out)
- eh_timed_out = scmd->device->host->hostt->eh_timed_out;
- else
- eh_timed_out = NULL;
+ rtn = scmd->device->host->hostt->eh_timed_out(scmd);
- if (eh_timed_out)
- rtn = eh_timed_out(scmd);
- switch (rtn) {
- case BLK_EH_NOT_HANDLED:
- break;
- default:
- return rtn;
- }
-
- if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
+ if (unlikely(rtn == BLK_EH_NOT_HANDLED &&
+ !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
scmd->result |= DID_TIME_OUT << 16;
scmd->result |= DID_TIME_OUT << 16;
- r
eturn
BLK_EH_HANDLED;
+ r
tn =
BLK_EH_HANDLED;
}
}
- return
BLK_EH_NOT_HANDLED
;
+ return
rtn
;
}
/**
}
/**
@@
-393,9
+382,13
@@
static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
* who knows? FIXME(eric)
*/
return SUCCESS;
* who knows? FIXME(eric)
*/
return SUCCESS;
+ case RESERVATION_CONFLICT:
+ /*
+ * let issuer deal with this, it could be just fine
+ */
+ return SUCCESS;
case BUSY:
case QUEUE_FULL:
case BUSY:
case QUEUE_FULL:
- case RESERVATION_CONFLICT:
default:
return FAILED;
}
default:
return FAILED;
}
@@
-652,9
+645,9
@@
EXPORT_SYMBOL(scsi_eh_prep_cmnd);
/**
* scsi_eh_restore_cmnd - Restore a scsi command info as part of error recory
* @scmd: SCSI command structure to restore
/**
* scsi_eh_restore_cmnd - Restore a scsi command info as part of error recory
* @scmd: SCSI command structure to restore
- * @ses: saved information from a coresponding call to scsi_
prep_eh
_cmnd
+ * @ses: saved information from a coresponding call to scsi_
eh_prep
_cmnd
*
*
- * Undo any damage done by above scsi_
prep_eh
_cmnd().
+ * Undo any damage done by above scsi_
eh_prep
_cmnd().
*/
void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
{
*/
void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
{
@@
-732,6
+725,9
@@
static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
case NEEDS_RETRY:
case FAILED:
break;
case NEEDS_RETRY:
case FAILED:
break;
+ case ADD_TO_MLQUEUE:
+ rtn = NEEDS_RETRY;
+ break;
default:
rtn = FAILED;
break;
default:
rtn = FAILED;
break;
@@
-932,8
+928,7
@@
static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
int i, rtn = NEEDS_RETRY;
for (i = 0; rtn == NEEDS_RETRY && i < 2; i++)
int i, rtn = NEEDS_RETRY;
for (i = 0; rtn == NEEDS_RETRY && i < 2; i++)
- rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
- scmd->device->timeout, 0);
+ rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, scmd->device->request_queue->rq_timeout, 0);
if (rtn == SUCCESS)
return 0;
if (rtn == SUCCESS)
return 0;
@@
-1065,10
+1060,10
@@
static int scsi_eh_target_reset(struct Scsi_Host *shost,
struct list_head *done_q)
{
struct scsi_cmnd *scmd, *tgtr_scmd, *next;
struct list_head *done_q)
{
struct scsi_cmnd *scmd, *tgtr_scmd, *next;
- unsigned int id;
+ unsigned int id
= 0
;
int rtn;
int rtn;
-
for (id = 0; id <= shost->max_id; id++)
{
+
do
{
tgtr_scmd = NULL;
list_for_each_entry(scmd, work_q, eh_entry) {
if (id == scmd_id(scmd)) {
tgtr_scmd = NULL;
list_for_each_entry(scmd, work_q, eh_entry) {
if (id == scmd_id(scmd)) {
@@
-1076,8
+1071,18
@@
static int scsi_eh_target_reset(struct Scsi_Host *shost,
break;
}
}
break;
}
}
+ if (!tgtr_scmd) {
+ /* not one exactly equal; find the next highest */
+ list_for_each_entry(scmd, work_q, eh_entry) {
+ if (scmd_id(scmd) > id &&
+ (!tgtr_scmd ||
+ scmd_id(tgtr_scmd) > scmd_id(scmd)))
+ tgtr_scmd = scmd;
+ }
+ }
if (!tgtr_scmd)
if (!tgtr_scmd)
- continue;
+ /* no more commands, that's it */
+ break;
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset "
"to target %d\n",
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset "
"to target %d\n",
@@
-1096,7
+1101,8
@@
static int scsi_eh_target_reset(struct Scsi_Host *shost,
" failed target: "
"%d\n",
current->comm, id));
" failed target: "
"%d\n",
current->comm, id));
- }
+ id++;
+ } while(id != 0);
return list_empty(work_q);
}
return list_empty(work_q);
}
@@
-1329,9
+1335,10
@@
int scsi_decide_disposition(struct scsi_cmnd *scmd)
* LLD/transport was disrupted during processing of the IO.
* The transport class is now blocked/blocking,
* and the transport will decide what to do with the IO
* LLD/transport was disrupted during processing of the IO.
* The transport class is now blocked/blocking,
* and the transport will decide what to do with the IO
- * based on its timers and recovery capablilities.
+ * based on its timers and recovery capablilities if
+ * there are enough retries.
*/
*/
-
return ADD_TO_MLQUEUE
;
+
goto maybe_retry
;
case DID_TRANSPORT_FAILFAST:
/*
* The transport decided to failfast the IO (most likely
case DID_TRANSPORT_FAILFAST:
/*
* The transport decided to failfast the IO (most likely
@@
-1394,8
+1401,9
@@
int scsi_decide_disposition(struct scsi_cmnd *scmd)
return ADD_TO_MLQUEUE;
case GOOD:
case COMMAND_TERMINATED:
return ADD_TO_MLQUEUE;
case GOOD:
case COMMAND_TERMINATED:
- case TASK_ABORTED:
return SUCCESS;
return SUCCESS;
+ case TASK_ABORTED:
+ goto maybe_retry;
case CHECK_CONDITION:
rtn = scsi_check_sense(scmd);
if (rtn == NEEDS_RETRY)
case CHECK_CONDITION:
rtn = scsi_check_sense(scmd);
if (rtn == NEEDS_RETRY)
@@
-1440,41
+1448,48
@@
int scsi_decide_disposition(struct scsi_cmnd *scmd)
}
}
}
}
+static void eh_lock_door_done(struct request *req, int uptodate)
+{
+ __blk_put_request(req->q, req);
+}
+
/**
* scsi_eh_lock_door - Prevent medium removal for the specified device
* @sdev: SCSI device to prevent medium removal
*
* Locking:
/**
* scsi_eh_lock_door - Prevent medium removal for the specified device
* @sdev: SCSI device to prevent medium removal
*
* Locking:
- * We must be called from process context; scsi_allocate_request()
- * may sleep.
+ * We must be called from process context.
*
* Notes:
* We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the
* head of the devices request queue, and continue.
*
* Notes:
* We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the
* head of the devices request queue, and continue.
- *
- * Bugs:
- * scsi_allocate_request() may sleep waiting for existing requests to
- * be processed. However, since we haven't kicked off any request
- * processing for this host, this may deadlock.
- *
- * If scsi_allocate_request() fails for what ever reason, we
- * completely forget to lock the door.
*/
static void scsi_eh_lock_door(struct scsi_device *sdev)
{
*/
static void scsi_eh_lock_door(struct scsi_device *sdev)
{
- unsigned char cmnd[MAX_COMMAND_SIZE];
+ struct request *req;
+
+ /*
+ * blk_get_request with GFP_KERNEL (__GFP_WAIT) sleeps until a
+ * request becomes available
+ */
+ req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
-
cmn
d[0] = ALLOW_MEDIUM_REMOVAL;
-
cmn
d[1] = 0;
-
cmn
d[2] = 0;
-
cmn
d[3] = 0;
-
cmn
d[4] = SCSI_REMOVAL_PREVENT;
-
cmn
d[5] = 0;
+
req->cm
d[0] = ALLOW_MEDIUM_REMOVAL;
+
req->cm
d[1] = 0;
+
req->cm
d[2] = 0;
+
req->cm
d[3] = 0;
+
req->cm
d[4] = SCSI_REMOVAL_PREVENT;
+
req->cm
d[5] = 0;
- scsi_execute_async(sdev, cmnd, 6, DMA_NONE, NULL, 0, 0, 10 * HZ,
- 5, NULL, NULL, GFP_KERNEL);
-}
+ req->cmd_len = COMMAND_SIZE(req->cmd[0]);
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->cmd_flags |= REQ_QUIET;
+ req->timeout = 10 * HZ;
+ req->retries = 5;
+
+ blk_execute_rq_nowait(req->q, NULL, req, 1, eh_lock_door_done);
+}
/**
* scsi_restart_operations - restart io operations to the specified host.
/**
* scsi_restart_operations - restart io operations to the specified host.
@@
-1637,7
+1652,7
@@
int scsi_error_handler(void *data)
* We use TASK_INTERRUPTIBLE so that the thread is not
* counted against the load average as a running process.
* We never actually get interrupted because kthread_run
* We use TASK_INTERRUPTIBLE so that the thread is not
* counted against the load average as a running process.
* We never actually get interrupted because kthread_run
- * disables si
ng
al delivery for the created thread.
+ * disables si
gn
al delivery for the created thread.
*/
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
*/
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {