]> Pileus Git - ~andy/linux/blobdiff - drivers/scsi/scsi_lib.c
[SCSI] don't use __GFP_DMA for sense buffers if not required
[~andy/linux] / drivers / scsi / scsi_lib.c
index 199b02452259e4758e20d17047539472cbe11bb1..4cf902efbdbf14aa26422226491463aa05a2f7cc 100644 (file)
@@ -441,7 +441,7 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
 {
        cmd->serial_number = 0;
        cmd->resid = 0;
-       memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
+       memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
        if (cmd->cmd_len == 0)
                cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
 }
@@ -526,7 +526,7 @@ static void scsi_run_queue(struct request_queue *q)
        struct Scsi_Host *shost = sdev->host;
        unsigned long flags;
 
-       if (sdev->single_lun)
+       if (scsi_target(sdev)->single_lun)
                scsi_single_lun_run(sdev);
 
        spin_lock_irqsave(shost->host_lock, flags);
@@ -1104,7 +1104,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
  *
  * Returns:     0 on success
  *             BLKPREP_DEFER if the failure is retryable
- *             BLKPREP_KILL if the failure is fatal
  */
 static int scsi_init_io(struct scsi_cmnd *cmd)
 {
@@ -1138,17 +1137,9 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
         * each segment.
         */
        count = blk_rq_map_sg(req->q, req, cmd->request_buffer);
-       if (likely(count <= cmd->use_sg)) {
-               cmd->use_sg = count;
-               return BLKPREP_OK;
-       }
-
-       printk(KERN_ERR "Incorrect number of segments after building list\n");
-       printk(KERN_ERR "counted %d, received %d\n", count, cmd->use_sg);
-       printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
-                       req->current_nr_sectors);
-
-       return BLKPREP_KILL;
+       BUG_ON(count > cmd->use_sg);
+       cmd->use_sg = count;
+       return BLKPREP_OK;
 }
 
 static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
@@ -1559,7 +1550,7 @@ static void scsi_request_fn(struct request_queue *q)
 
                if (!scsi_host_queue_ready(q, shost, sdev))
                        goto not_ready;
-               if (sdev->single_lun) {
+               if (scsi_target(sdev)->single_lun) {
                        if (scsi_target(sdev)->starget_sdev_user &&
                            scsi_target(sdev)->starget_sdev_user != sdev)
                                goto not_ready;
@@ -1677,6 +1668,14 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
 
        if (!shost->use_clustering)
                clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+
+       /*
+        * set a reasonable default alignment on word boundaries: the
+        * host and device may alter it using
+        * blk_queue_update_dma_alignment() later.
+        */
+       blk_queue_dma_alignment(q, 0x03);
+
        return q;
 }
 EXPORT_SYMBOL(__scsi_alloc_queue);
@@ -1982,27 +1981,57 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
 }
 EXPORT_SYMBOL(scsi_mode_sense);
 
+/**
+ *     scsi_test_unit_ready - test if unit is ready
+ *     @sdev:  scsi device to change the state of.
+ *     @timeout: command timeout
+ *     @retries: number of retries before failing
+ *     @sshdr_external: Optional pointer to struct scsi_sense_hdr for
+ *             returning sense. Make sure that this is cleared before passing
+ *             in.
+ *
+ *     Returns zero if unsuccessful or an error if TUR failed.  For
+ *     removable media, a return of NOT_READY or UNIT_ATTENTION is
+ *     translated to success, with the ->changed flag updated.
+ **/
 int
-scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
+scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
+                    struct scsi_sense_hdr *sshdr_external)
 {
        char cmd[] = {
                TEST_UNIT_READY, 0, 0, 0, 0, 0,
        };
-       struct scsi_sense_hdr sshdr;
+       struct scsi_sense_hdr *sshdr;
        int result;
-       
-       result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
-                                 timeout, retries);
+
+       if (!sshdr_external)
+               sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
+       else
+               sshdr = sshdr_external;
+
+       /* try to eat the UNIT_ATTENTION if there are enough retries */
+       do {
+               result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
+                                         timeout, retries);
+       } while ((driver_byte(result) & DRIVER_SENSE) &&
+                sshdr && sshdr->sense_key == UNIT_ATTENTION &&
+                --retries);
+
+       if (!sshdr)
+               /* could not allocate sense buffer, so can't process it */
+               return result;
 
        if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) {
 
-               if ((scsi_sense_valid(&sshdr)) &&
-                   ((sshdr.sense_key == UNIT_ATTENTION) ||
-                    (sshdr.sense_key == NOT_READY))) {
+               if ((scsi_sense_valid(sshdr)) &&
+                   ((sshdr->sense_key == UNIT_ATTENTION) ||
+                    (sshdr->sense_key == NOT_READY))) {
                        sdev->changed = 1;
                        result = 0;
                }
        }
+       if (!sshdr_external)
+               kfree(sshdr);
        return result;
 }
 EXPORT_SYMBOL(scsi_test_unit_ready);