Merge branch 'sas-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/misc-2.6
[safe/jmp/linux-2.6] / drivers / scsi / scsi_transport_spi.c
index 9f070f0..4df21c9 100644 (file)
@@ -46,7 +46,6 @@
                                 * two cc/ua clears */
 
 /* Private data accessors (keep these out of the header file) */
-#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
 #define spi_dv_in_progress(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_in_progress)
 #define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex)
 
@@ -122,7 +121,7 @@ static int spi_execute(struct scsi_device *sdev, const void *cmd,
                        if (!sshdr)
                                sshdr = &sshdr_tmp;
 
-                       if (scsi_normalize_sense(sense, sizeof(*sense),
+                       if (scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE,
                                                 sshdr)
                            && sshdr->sense_key == UNIT_ATTENTION)
                                continue;
@@ -788,10 +787,12 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
        struct scsi_target *starget = sdev->sdev_target;
        struct Scsi_Host *shost = sdev->host;
        int len = sdev->inquiry_len;
+       int min_period = spi_min_period(starget);
+       int max_width = spi_max_width(starget);
        /* first set us up for narrow async */
        DV_SET(offset, 0);
        DV_SET(width, 0);
-       
+
        if (spi_dv_device_compare_inquiry(sdev, buffer, buffer, DV_LOOPS)
            != SPI_COMPARE_SUCCESS) {
                starget_printk(KERN_ERR, starget, "Domain Validation Initial Inquiry Failed\n");
@@ -799,9 +800,13 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
                return;
        }
 
+       if (!scsi_device_wide(sdev)) {
+               spi_max_width(starget) = 0;
+               max_width = 0;
+       }
+
        /* test width */
-       if (i->f->set_width && spi_max_width(starget) &&
-           scsi_device_wide(sdev)) {
+       if (i->f->set_width && max_width) {
                i->f->set_width(starget, 1);
 
                if (spi_dv_device_compare_inquiry(sdev, buffer,
@@ -810,6 +815,11 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
                    != SPI_COMPARE_SUCCESS) {
                        starget_printk(KERN_ERR, starget, "Wide Transfers Fail\n");
                        i->f->set_width(starget, 0);
+                       /* Make sure we don't force wide back on by asking
+                        * for a transfer period that requires it */
+                       max_width = 0;
+                       if (min_period < 10)
+                               min_period = 10;
                }
        }
 
@@ -829,7 +839,8 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
 
        /* now set up to the maximum */
        DV_SET(offset, spi_max_offset(starget));
-       DV_SET(period, spi_min_period(starget));
+       DV_SET(period, min_period);
+
        /* try QAS requests; this should be harmless to set if the
         * target supports it */
        if (scsi_device_qas(sdev)) {
@@ -838,14 +849,14 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
                DV_SET(qas, 0);
        }
 
-       if (scsi_device_ius(sdev) && spi_min_period(starget) < 9) {
+       if (scsi_device_ius(sdev) && min_period < 9) {
                /* This u320 (or u640). Set IU transfers */
                DV_SET(iu, 1);
                /* Then set the optional parameters */
                DV_SET(rd_strm, 1);
                DV_SET(wr_flow, 1);
                DV_SET(rti, 1);
-               if (spi_min_period(starget) == 8)
+               if (min_period == 8)
                        DV_SET(pcomp_en, 1);
        } else {
                DV_SET(iu, 0);
@@ -863,6 +874,10 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
        } else {
                DV_SET(dt, 1);
        }
+       /* set width last because it will pull all the other
+        * parameters down to required values */
+       DV_SET(width, max_width);
+
        /* Do the read only INQUIRY tests */
        spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len,
                       spi_dv_device_compare_inquiry);
@@ -964,9 +979,10 @@ struct work_queue_wrapper {
 };
 
 static void
-spi_dv_device_work_wrapper(void *data)
+spi_dv_device_work_wrapper(struct work_struct *work)
 {
-       struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
+       struct work_queue_wrapper *wqw =
+               container_of(work, struct work_queue_wrapper, work);
        struct scsi_device *sdev = wqw->sdev;
 
        kfree(wqw);
@@ -1006,7 +1022,7 @@ spi_schedule_dv_device(struct scsi_device *sdev)
                return;
        }
 
-       INIT_WORK(&wqw->work, spi_dv_device_work_wrapper, wqw);
+       INIT_WORK(&wqw->work, spi_dv_device_work_wrapper);
        wqw->sdev = sdev;
 
        schedule_work(&wqw->work);