Merge branch 'intx' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/misc-2.6
[pandora-kernel.git] / drivers / scsi / scsi_error.c
index 6a5b731..2ecb6ff 100644 (file)
@@ -453,21 +453,32 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
 }
 
 /**
- * scsi_send_eh_cmnd  - send a cmd to a device as part of error recovery.
- * @scmd:      SCSI Cmd to send.
- * @timeout:   Timeout for cmd.
+ * scsi_send_eh_cmnd  - submit a scsi command as part of error recory
+ * @scmd:       SCSI command structure to hijack
+ * @cmnd:       CDB to send
+ * @cmnd_size:  size in bytes of @cmnd
+ * @timeout:    timeout for this request
+ * @copy_sense: request sense data if set to 1
+ *
+ * This function is used to send a scsi command down to a target device
+ * as part of the error recovery process.  If @copy_sense is 0 the command
+ * sent must be one that does not transfer any data.  If @copy_sense is 1
+ * the command must be REQUEST_SENSE and this functions copies out the
+ * sense buffer it got into @scmd->sense_buffer.
  *
  * Return value:
  *    SUCCESS or FAILED or NEEDS_RETRY
  **/
-static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout, int copy_sense)
+static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
+                            int cmnd_size, int timeout, int copy_sense)
 {
        struct scsi_device *sdev = scmd->device;
        struct Scsi_Host *shost = sdev->host;
        int old_result = scmd->result;
-       DECLARE_COMPLETION(done);
+       DECLARE_COMPLETION_ONSTACK(done);
        unsigned long timeleft;
        unsigned long flags;
+       struct scatterlist sgl;
        unsigned char old_cmnd[MAX_COMMAND_SIZE];
        enum dma_data_direction old_data_direction;
        unsigned short old_use_sg;
@@ -490,25 +501,33 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout, int copy_sense
        old_cmd_len = scmd->cmd_len;
        old_use_sg = scmd->use_sg;
 
+       memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+       memcpy(scmd->cmnd, cmnd, cmnd_size);
+
        if (copy_sense) {
-               int gfp_mask = GFP_ATOMIC;
+               gfp_t gfp_mask = GFP_ATOMIC;
 
                if (shost->hostt->unchecked_isa_dma)
                        gfp_mask |= __GFP_DMA;
 
-               scmd->sc_data_direction = DMA_FROM_DEVICE;
-               scmd->request_bufflen = 252;
-               scmd->request_buffer = kzalloc(scmd->request_bufflen, gfp_mask);
-               if (!scmd->request_buffer)
+               sgl.page = alloc_page(gfp_mask);
+               if (!sgl.page)
                        return FAILED;
+               sgl.offset = 0;
+               sgl.length = 252;
+
+               scmd->sc_data_direction = DMA_FROM_DEVICE;
+               scmd->request_bufflen = sgl.length;
+               scmd->request_buffer = &sgl;
+               scmd->use_sg = 1;
        } else {
                scmd->request_buffer = NULL;
                scmd->request_bufflen = 0;
                scmd->sc_data_direction = DMA_NONE;
+               scmd->use_sg = 0;
        }
 
        scmd->underflow = 0;
-       scmd->use_sg = 0;
        scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
 
        if (sdev->scsi_level <= SCSI_2)
@@ -579,7 +598,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout, int copy_sense
                        memcpy(scmd->sense_buffer, scmd->request_buffer,
                               sizeof(scmd->sense_buffer));
                }
-               kfree(scmd->request_buffer);
+               __free_page(sgl.page);
        }
 
 
@@ -610,8 +629,7 @@ static int scsi_request_sense(struct scsi_cmnd *scmd)
        static unsigned char generic_sense[6] =
                {REQUEST_SENSE, 0, 0, 0, 252, 0};
 
-       memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense));
-       return scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT, 1);
+       return scsi_send_eh_cmnd(scmd, generic_sense, 6, SENSE_TIMEOUT, 1);
 }
 
 /**
@@ -736,10 +754,7 @@ static int scsi_eh_tur(struct scsi_cmnd *scmd)
        int retry_cnt = 1, rtn;
 
 retry_tur:
-       memcpy(scmd->cmnd, tur_command, sizeof(tur_command));
-
-
-       rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT, 0);
+       rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0);
 
        SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
                __FUNCTION__, scmd, rtn));
@@ -839,8 +854,8 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
        if (scmd->device->allow_restart) {
                int rtn;
 
-               memcpy(scmd->cmnd, stu_command, sizeof(stu_command));
-               rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT, 0);
+               rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
+                                       START_UNIT_TIMEOUT, 0);
                if (rtn == SUCCESS)
                        return 0;
        }