]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi_error.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/holtmann/bluet...
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi_error.c
index 221f31e36d26e5c4f7bfe88b7abde0b2996c982e..006a95916f72ae4aff8cae52db9122a9d5e4bf9c 100644 (file)
@@ -298,6 +298,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
  */
 static int scsi_check_sense(struct scsi_cmnd *scmd)
 {
+       struct scsi_device *sdev = scmd->device;
        struct scsi_sense_hdr sshdr;
 
        if (! scsi_command_normalize_sense(scmd, &sshdr))
@@ -306,6 +307,16 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
        if (scsi_sense_is_deferred(&sshdr))
                return NEEDS_RETRY;
 
+       if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh &&
+                       sdev->scsi_dh_data->scsi_dh->check_sense) {
+               int rc;
+
+               rc = sdev->scsi_dh_data->scsi_dh->check_sense(sdev, &sshdr);
+               if (rc != SCSI_RETURN_NOT_HANDLED)
+                       return rc;
+               /* handler does not care. Drop down to default handling */
+       }
+
        /*
         * Previous logic looked for FILEMARK, EOM or ILI which are
         * mainly associated with tapes and returned SUCCESS.
@@ -626,7 +637,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
  * @scmd:       SCSI command structure to hijack
  * @ses:        structure to save restore information
  * @cmnd:       CDB to send. Can be NULL if no new cmnd is needed
- * @cmnd_size:  size in bytes of @cmnd
+ * @cmnd_size:  size in bytes of @cmnd (must be <= BLK_MAX_CDB)
  * @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored)
  *
  * This function is used to save a scsi command information before re-execution
@@ -648,12 +659,14 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
         * command.
         */
        ses->cmd_len = scmd->cmd_len;
-       memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
+       ses->cmnd = scmd->cmnd;
        ses->data_direction = scmd->sc_data_direction;
        ses->sdb = scmd->sdb;
        ses->next_rq = scmd->request->next_rq;
        ses->result = scmd->result;
 
+       scmd->cmnd = ses->eh_cmnd;
+       memset(scmd->cmnd, 0, BLK_MAX_CDB);
        memset(&scmd->sdb, 0, sizeof(scmd->sdb));
        scmd->request->next_rq = NULL;
 
@@ -665,14 +678,13 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
                scmd->sdb.table.sgl = &ses->sense_sgl;
                scmd->sc_data_direction = DMA_FROM_DEVICE;
                scmd->sdb.table.nents = 1;
-               memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
                scmd->cmnd[0] = REQUEST_SENSE;
                scmd->cmnd[4] = scmd->sdb.length;
                scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
        } else {
                scmd->sc_data_direction = DMA_NONE;
                if (cmnd) {
-                       memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+                       BUG_ON(cmnd_size > BLK_MAX_CDB);
                        memcpy(scmd->cmnd, cmnd, cmnd_size);
                        scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
                }
@@ -705,7 +717,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
         * Restore original data
         */
        scmd->cmd_len = ses->cmd_len;
-       memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
+       scmd->cmnd = ses->cmnd;
        scmd->sc_data_direction = ses->data_direction;
        scmd->sdb = ses->sdb;
        scmd->request->next_rq = ses->next_rq;
@@ -1771,11 +1783,12 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
        unsigned long flags;
        int rtn;
 
+       blk_rq_init(NULL, &req);
        scmd->request = &req;
        memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
 
-       memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
-    
+       scmd->cmnd = req.cmd;
+
        scmd->scsi_done         = scsi_reset_provider_done_command;
        memset(&scmd->sdb, 0, sizeof(scmd->sdb));