|
|
|
@@ -60,7 +60,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd);
|
|
|
|
|
#define HOST_RESET_SETTLE_TIME (10)
|
|
|
|
|
|
|
|
|
|
static int scsi_eh_try_stu(struct scsi_cmnd *scmd);
|
|
|
|
|
static enum scsi_disposition scsi_try_to_abort_cmd(struct scsi_host_template *,
|
|
|
|
|
static int scsi_try_to_abort_cmd(struct scsi_host_template *,
|
|
|
|
|
struct scsi_cmnd *);
|
|
|
|
|
|
|
|
|
|
void scsi_eh_wakeup(struct Scsi_Host *shost)
|
|
|
|
@@ -140,7 +140,7 @@ scmd_eh_abort_handler(struct work_struct *work)
|
|
|
|
|
struct scsi_cmnd *scmd =
|
|
|
|
|
container_of(work, struct scsi_cmnd, abort_work.work);
|
|
|
|
|
struct scsi_device *sdev = scmd->device;
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int rtn;
|
|
|
|
|
|
|
|
|
|
if (scsi_host_eh_past_deadline(sdev->host)) {
|
|
|
|
|
SCSI_LOG_ERROR_RECOVERY(3,
|
|
|
|
@@ -478,7 +478,7 @@ static void scsi_report_sense(struct scsi_device *sdev,
|
|
|
|
|
* When a deferred error is detected the current command has
|
|
|
|
|
* not been executed and needs retrying.
|
|
|
|
|
*/
|
|
|
|
|
enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
|
|
|
|
|
int scsi_check_sense(struct scsi_cmnd *scmd)
|
|
|
|
|
{
|
|
|
|
|
struct scsi_device *sdev = scmd->device;
|
|
|
|
|
struct scsi_sense_hdr sshdr;
|
|
|
|
@@ -492,7 +492,7 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
|
|
|
|
|
return NEEDS_RETRY;
|
|
|
|
|
|
|
|
|
|
if (sdev->handler && sdev->handler->check_sense) {
|
|
|
|
|
enum scsi_disposition rc;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
rc = sdev->handler->check_sense(sdev, &sshdr);
|
|
|
|
|
if (rc != SCSI_RETURN_NOT_HANDLED)
|
|
|
|
@@ -703,7 +703,7 @@ static void scsi_handle_queue_full(struct scsi_device *sdev)
|
|
|
|
|
* don't allow for the possibility of retries here, and we are a lot
|
|
|
|
|
* more restrictive about what we consider acceptable.
|
|
|
|
|
*/
|
|
|
|
|
static enum scsi_disposition scsi_eh_completed_normally(struct scsi_cmnd *scmd)
|
|
|
|
|
static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* first check the host byte, to see if there is anything in there
|
|
|
|
@@ -784,10 +784,10 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
|
|
|
|
|
* scsi_try_host_reset - ask host adapter to reset itself
|
|
|
|
|
* @scmd: SCSI cmd to send host reset.
|
|
|
|
|
*/
|
|
|
|
|
static enum scsi_disposition scsi_try_host_reset(struct scsi_cmnd *scmd)
|
|
|
|
|
static int scsi_try_host_reset(struct scsi_cmnd *scmd)
|
|
|
|
|
{
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int rtn;
|
|
|
|
|
struct Scsi_Host *host = scmd->device->host;
|
|
|
|
|
struct scsi_host_template *hostt = host->hostt;
|
|
|
|
|
|
|
|
|
@@ -814,10 +814,10 @@ static enum scsi_disposition scsi_try_host_reset(struct scsi_cmnd *scmd)
|
|
|
|
|
* scsi_try_bus_reset - ask host to perform a bus reset
|
|
|
|
|
* @scmd: SCSI cmd to send bus reset.
|
|
|
|
|
*/
|
|
|
|
|
static enum scsi_disposition scsi_try_bus_reset(struct scsi_cmnd *scmd)
|
|
|
|
|
static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
|
|
|
|
|
{
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int rtn;
|
|
|
|
|
struct Scsi_Host *host = scmd->device->host;
|
|
|
|
|
struct scsi_host_template *hostt = host->hostt;
|
|
|
|
|
|
|
|
|
@@ -856,10 +856,10 @@ static void __scsi_report_device_reset(struct scsi_device *sdev, void *data)
|
|
|
|
|
* timer on it, and set the host back to a consistent state prior to
|
|
|
|
|
* returning.
|
|
|
|
|
*/
|
|
|
|
|
static enum scsi_disposition scsi_try_target_reset(struct scsi_cmnd *scmd)
|
|
|
|
|
static int scsi_try_target_reset(struct scsi_cmnd *scmd)
|
|
|
|
|
{
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int rtn;
|
|
|
|
|
struct Scsi_Host *host = scmd->device->host;
|
|
|
|
|
struct scsi_host_template *hostt = host->hostt;
|
|
|
|
|
|
|
|
|
@@ -887,9 +887,9 @@ static enum scsi_disposition scsi_try_target_reset(struct scsi_cmnd *scmd)
|
|
|
|
|
* timer on it, and set the host back to a consistent state prior to
|
|
|
|
|
* returning.
|
|
|
|
|
*/
|
|
|
|
|
static enum scsi_disposition scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
|
|
|
|
|
static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
|
|
|
|
|
{
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int rtn;
|
|
|
|
|
struct scsi_host_template *hostt = scmd->device->host->hostt;
|
|
|
|
|
|
|
|
|
|
if (!hostt->eh_device_reset_handler)
|
|
|
|
@@ -918,8 +918,8 @@ static enum scsi_disposition scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
|
|
|
|
|
* if the device is temporarily unavailable (eg due to a
|
|
|
|
|
* link down on FibreChannel)
|
|
|
|
|
*/
|
|
|
|
|
static enum scsi_disposition
|
|
|
|
|
scsi_try_to_abort_cmd(struct scsi_host_template *hostt, struct scsi_cmnd *scmd)
|
|
|
|
|
static int scsi_try_to_abort_cmd(struct scsi_host_template *hostt,
|
|
|
|
|
struct scsi_cmnd *scmd)
|
|
|
|
|
{
|
|
|
|
|
if (!hostt->eh_abort_handler)
|
|
|
|
|
return FAILED;
|
|
|
|
@@ -1052,8 +1052,8 @@ EXPORT_SYMBOL(scsi_eh_restore_cmnd);
|
|
|
|
|
* Return value:
|
|
|
|
|
* SUCCESS or FAILED or NEEDS_RETRY
|
|
|
|
|
*/
|
|
|
|
|
static enum scsi_disposition scsi_send_eh_cmnd(struct scsi_cmnd *scmd,
|
|
|
|
|
unsigned char *cmnd, int cmnd_size, int timeout, unsigned sense_bytes)
|
|
|
|
|
static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
|
|
|
|
|
int cmnd_size, int timeout, unsigned sense_bytes)
|
|
|
|
|
{
|
|
|
|
|
struct scsi_device *sdev = scmd->device;
|
|
|
|
|
struct Scsi_Host *shost = sdev->host;
|
|
|
|
@@ -1161,13 +1161,12 @@ retry:
|
|
|
|
|
* that we obtain it on our own. This function will *not* return until
|
|
|
|
|
* the command either times out, or it completes.
|
|
|
|
|
*/
|
|
|
|
|
static enum scsi_disposition scsi_request_sense(struct scsi_cmnd *scmd)
|
|
|
|
|
static int scsi_request_sense(struct scsi_cmnd *scmd)
|
|
|
|
|
{
|
|
|
|
|
return scsi_send_eh_cmnd(scmd, NULL, 0, scmd->device->eh_timeout, ~0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum scsi_disposition
|
|
|
|
|
scsi_eh_action(struct scsi_cmnd *scmd, enum scsi_disposition rtn)
|
|
|
|
|
static int scsi_eh_action(struct scsi_cmnd *scmd, int rtn)
|
|
|
|
|
{
|
|
|
|
|
if (!blk_rq_is_passthrough(scmd->request)) {
|
|
|
|
|
struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd);
|
|
|
|
@@ -1220,7 +1219,7 @@ int scsi_eh_get_sense(struct list_head *work_q,
|
|
|
|
|
{
|
|
|
|
|
struct scsi_cmnd *scmd, *next;
|
|
|
|
|
struct Scsi_Host *shost;
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int rtn;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If SCSI_EH_ABORT_SCHEDULED has been set, it is timeout IO,
|
|
|
|
@@ -1298,8 +1297,7 @@ EXPORT_SYMBOL_GPL(scsi_eh_get_sense);
|
|
|
|
|
static int scsi_eh_tur(struct scsi_cmnd *scmd)
|
|
|
|
|
{
|
|
|
|
|
static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
|
|
|
|
|
int retry_cnt = 1;
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int retry_cnt = 1, rtn;
|
|
|
|
|
|
|
|
|
|
retry_tur:
|
|
|
|
|
rtn = scsi_send_eh_cmnd(scmd, tur_command, 6,
|
|
|
|
@@ -1387,8 +1385,7 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
|
|
|
|
|
static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
|
|
|
|
|
|
|
|
|
|
if (scmd->device->allow_restart) {
|
|
|
|
|
int i;
|
|
|
|
|
enum scsi_disposition rtn = NEEDS_RETRY;
|
|
|
|
|
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->request_queue->rq_timeout, 0);
|
|
|
|
@@ -1482,7 +1479,7 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
|
|
|
|
|
{
|
|
|
|
|
struct scsi_cmnd *scmd, *bdr_scmd, *next;
|
|
|
|
|
struct scsi_device *sdev;
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int rtn;
|
|
|
|
|
|
|
|
|
|
shost_for_each_device(sdev, shost) {
|
|
|
|
|
if (scsi_host_eh_past_deadline(shost)) {
|
|
|
|
@@ -1549,7 +1546,7 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
|
|
|
|
|
|
|
|
|
|
while (!list_empty(&tmp_list)) {
|
|
|
|
|
struct scsi_cmnd *next, *scmd;
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int rtn;
|
|
|
|
|
unsigned int id;
|
|
|
|
|
|
|
|
|
|
if (scsi_host_eh_past_deadline(shost)) {
|
|
|
|
@@ -1607,7 +1604,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
|
|
|
|
|
struct scsi_cmnd *scmd, *chan_scmd, *next;
|
|
|
|
|
LIST_HEAD(check_list);
|
|
|
|
|
unsigned int channel;
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int rtn;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* we really want to loop over the various channels, and do this on
|
|
|
|
@@ -1678,7 +1675,7 @@ static int scsi_eh_host_reset(struct Scsi_Host *shost,
|
|
|
|
|
{
|
|
|
|
|
struct scsi_cmnd *scmd, *next;
|
|
|
|
|
LIST_HEAD(check_list);
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int rtn;
|
|
|
|
|
|
|
|
|
|
if (!list_empty(work_q)) {
|
|
|
|
|
scmd = list_entry(work_q->next,
|
|
|
|
@@ -1784,9 +1781,9 @@ check_type:
|
|
|
|
|
* doesn't require the error handler read (i.e. we don't need to
|
|
|
|
|
* abort/reset), this function should return SUCCESS.
|
|
|
|
|
*/
|
|
|
|
|
enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *scmd)
|
|
|
|
|
int scsi_decide_disposition(struct scsi_cmnd *scmd)
|
|
|
|
|
{
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int rtn;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* if the device is offline, then we clearly just pass the result back
|
|
|
|
@@ -2342,8 +2339,7 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg)
|
|
|
|
|
struct Scsi_Host *shost = dev->host;
|
|
|
|
|
struct request *rq;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
int error = 0, val;
|
|
|
|
|
enum scsi_disposition rtn;
|
|
|
|
|
int error = 0, rtn, val;
|
|
|
|
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
|
|
|
|
|
return -EACCES;
|
|
|
|
|