]> err.no Git - linux-2.6/blobdiff - drivers/scsi/aacraid/aachba.c
Merge branch 'for-2.6.26' of master.kernel.org:/pub/scm/linux/kernel/git/jwboyer...
[linux-2.6] / drivers / scsi / aacraid / aachba.c
index bfd0e64964accc6e8317c50338725d4fc8db6ad5..aa4e77c252735c593e523ae4a9f516045b674733 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/slab.h>
 #include <linux/completion.h>
 #include <linux/blkdev.h>
-#include <asm/semaphore.h>
 #include <asm/uaccess.h>
 #include <linux/highmem.h> /* For flush_kernel_dcache_page */
 
@@ -144,51 +143,77 @@ static char *aac_get_status_string(u32 status);
  */
 
 static int nondasd = -1;
-static int aac_cache = 0;
+static int aac_cache;
 static int dacmode = -1;
-
+int aac_msi;
 int aac_commit = -1;
 int startup_timeout = 180;
 int aif_timeout = 120;
 
 module_param(nondasd, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
+MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices."
+       " 0=off, 1=on");
 module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n\tbit 0 - Disable FUA in WRITE SCSI commands\n\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n\tbit 2 - Disable only if Battery not protecting Cache");
+MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n"
+       "\tbit 0 - Disable FUA in WRITE SCSI commands\n"
+       "\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n"
+       "\tbit 2 - Disable only if Battery not protecting Cache");
 module_param(dacmode, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on");
+MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC."
+       " 0=off, 1=on");
 module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the adapter for foreign arrays.\nThis is typically needed in systems that do not have a BIOS. 0=off, 1=on");
+MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the"
+       " adapter for foreign arrays.\n"
+       "This is typically needed in systems that do not have a BIOS."
+       " 0=off, 1=on");
+module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(msi, "IRQ handling."
+       " 0=PIC(default), 1=MSI, 2=MSI-X(unsupported, uses MSI)");
 module_param(startup_timeout, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for adapter to have it's kernel up and\nrunning. This is typically adjusted for large systems that do not have a BIOS.");
+MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for"
+       " adapter to have it's kernel up and\n"
+       "running. This is typically adjusted for large systems that do not"
+       " have a BIOS.");
 module_param(aif_timeout, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(aif_timeout, "The duration of time in seconds to wait for applications to pick up AIFs before\nderegistering them. This is typically adjusted for heavily burdened systems.");
+MODULE_PARM_DESC(aif_timeout, "The duration of time in seconds to wait for"
+       " applications to pick up AIFs before\n"
+       "deregistering them. This is typically adjusted for heavily burdened"
+       " systems.");
 
 int numacb = -1;
 module_param(numacb, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control blocks (FIB) allocated. Valid values are 512 and down. Default is to use suggestion from Firmware.");
+MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control"
+       " blocks (FIB) allocated. Valid values are 512 and down. Default is"
+       " to use suggestion from Firmware.");
 
 int acbsize = -1;
 module_param(acbsize, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware.");
+MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB)"
+       " size. Valid values are 512, 2048, 4096 and 8192. Default is to use"
+       " suggestion from Firmware.");
 
 int update_interval = 30 * 60;
 module_param(update_interval, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync updates issued to adapter.");
+MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync"
+       " updates issued to adapter.");
 
 int check_interval = 24 * 60 * 60;
 module_param(check_interval, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health checks.");
+MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health"
+       " checks.");
 
 int aac_check_reset = 1;
 module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter. a value of -1 forces the reset to adapters programmed to ignore it.");
+MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the"
+       " adapter. a value of -1 forces the reset to adapters programmed to"
+       " ignore it.");
 
 int expose_physicals = -1;
 module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on");
+MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays."
+       " -1=protect 0=off, 1=on");
 
-int aac_reset_devices = 0;
+int aac_reset_devices;
 module_param_named(reset_devices, aac_reset_devices, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(reset_devices, "Force an adapter reset at initialization.");
 
@@ -353,24 +378,6 @@ int aac_get_containers(struct aac_dev *dev)
        return status;
 }
 
-static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigned int offset, unsigned int len)
-{
-       void *buf;
-       int transfer_len;
-       struct scatterlist *sg = scsi_sglist(scsicmd);
-
-       buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
-       transfer_len = min(sg->length, len + offset);
-
-       transfer_len -= offset;
-       if (buf && transfer_len > 0)
-               memcpy(buf + offset, data, transfer_len);
-
-       flush_kernel_dcache_page(kmap_atomic_to_page(buf - sg->offset));
-       kunmap_atomic(buf - sg->offset, KM_IRQ0);
-
-}
-
 static void get_container_name_callback(void *context, struct fib * fibptr)
 {
        struct aac_get_name_resp * get_name_reply;
@@ -393,14 +400,17 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
                while (*sp == ' ')
                        ++sp;
                if (*sp) {
+                       struct inquiry_data inq;
                        char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)];
                        int count = sizeof(d);
                        char *dp = d;
                        do {
                                *dp++ = (*sp) ? *sp++ : ' ';
                        } while (--count > 0);
-                       aac_internal_transfer(scsicmd, d,
-                         offsetof(struct inquiry_data, inqd_pid), sizeof(d));
+
+                       scsi_sg_copy_to_buffer(scsicmd, &inq, sizeof(inq));
+                       memcpy(inq.inqd_pid, d, sizeof(d));
+                       scsi_sg_copy_from_buffer(scsicmd, &inq, sizeof(inq));
                }
        }
 
@@ -488,6 +498,11 @@ static void _aac_probe_container2(void * context, struct fib * fibptr)
                    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
                    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
                        fsa_dev_ptr->valid = 1;
+                       /* sense_key holds the current state of the spin-up */
+                       if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY))
+                               fsa_dev_ptr->sense_data.sense_key = NOT_READY;
+                       else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY)
+                               fsa_dev_ptr->sense_data.sense_key = NO_SENSE;
                        fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
                        fsa_dev_ptr->size
                          = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
@@ -785,7 +800,7 @@ static void get_container_serial_callback(void *context, struct fib * fibptr)
                sp[2] = 0;
                sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",
                  le32_to_cpu(get_serial_reply->uid));
-               aac_internal_transfer(scsicmd, sp, 0, sizeof(sp));
+               scsi_sg_copy_from_buffer(scsicmd, sp, sizeof(sp));
        }
 
        scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
@@ -1305,7 +1320,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
                        tmp>>24,(tmp>>16)&0xff,tmp&0xff,
                        le32_to_cpu(dev->adapter_info.biosbuild));
                buffer[0] = '\0';
-               if (aac_show_serial_number(
+               if (aac_get_serial_number(
                  shost_to_class(dev->scsi_host_ptr), buffer))
                        printk(KERN_INFO "%s%d: serial %s",
                          dev->name, dev->id, buffer);
@@ -1315,7 +1330,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
                          (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
                          dev->supplement_adapter_info.VpdInfo.Tsid);
                }
-               if (!aac_check_reset || ((aac_check_reset != 1) &&
+               if (!aac_check_reset || ((aac_check_reset == 1) &&
                  (dev->supplement_adapter_info.SupportedOptions2 &
                  AAC_OPTION_IGNORE_RESET))) {
                        printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
@@ -1353,13 +1368,14 @@ int aac_get_adapter_info(struct aac_dev* dev)
 
        if (nondasd != -1)
                dev->nondasd_support = (nondasd!=0);
-       if(dev->nondasd_support != 0) {
+       if (dev->nondasd_support && !dev->in_reset)
                printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
-       }
 
        dev->dac_support = 0;
        if( (sizeof(dma_addr_t) > 4) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){
-               printk(KERN_INFO "%s%d: 64bit support enabled.\n", dev->name, dev->id);
+               if (!dev->in_reset)
+                       printk(KERN_INFO "%s%d: 64bit support enabled.\n",
+                               dev->name, dev->id);
                dev->dac_support = 1;
        }
 
@@ -1369,8 +1385,9 @@ int aac_get_adapter_info(struct aac_dev* dev)
        if(dev->dac_support != 0) {
                if (!pci_set_dma_mask(dev->pdev, DMA_64BIT_MASK) &&
                        !pci_set_consistent_dma_mask(dev->pdev, DMA_64BIT_MASK)) {
-                       printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n",
-                               dev->name, dev->id);
+                       if (!dev->in_reset)
+                               printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n",
+                                       dev->name, dev->id);
                } else if (!pci_set_dma_mask(dev->pdev, DMA_32BIT_MASK) &&
                        !pci_set_consistent_dma_mask(dev->pdev, DMA_32BIT_MASK)) {
                        printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n",
@@ -1497,20 +1514,35 @@ static void io_callback(void *context, struct fib * fibptr)
        scsi_dma_unmap(scsicmd);
 
        readreply = (struct aac_read_reply *)fib_data(fibptr);
-       if (le32_to_cpu(readreply->status) == ST_OK)
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-       else {
+       switch (le32_to_cpu(readreply->status)) {
+       case ST_OK:
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                       SAM_STAT_GOOD;
+               dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE;
+               break;
+       case ST_NOT_READY:
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                       SAM_STAT_CHECK_CONDITION;
+               set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY,
+                 SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0);
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                      min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+                            SCSI_SENSE_BUFFERSIZE));
+               break;
+       default:
 #ifdef AAC_DETAILED_STATUS_INFO
                printk(KERN_WARNING "io_callback: io failed, status = %d\n",
                  le32_to_cpu(readreply->status));
 #endif
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                       SAM_STAT_CHECK_CONDITION;
                set_sense(&dev->fsa_dev[cid].sense_data,
                  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
                  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
                memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
                       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
                             SCSI_SENSE_BUFFERSIZE));
+               break;
        }
        aac_fib_complete(fibptr);
        aac_fib_free(fibptr);
@@ -1851,6 +1883,84 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
        return SCSI_MLQUEUE_HOST_BUSY;
 }
 
+static void aac_start_stop_callback(void *context, struct fib *fibptr)
+{
+       struct scsi_cmnd *scsicmd = context;
+
+       if (!aac_valid_context(scsicmd, fibptr))
+               return;
+
+       BUG_ON(fibptr == NULL);
+
+       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+
+       aac_fib_complete(fibptr);
+       aac_fib_free(fibptr);
+       scsicmd->scsi_done(scsicmd);
+}
+
+static int aac_start_stop(struct scsi_cmnd *scsicmd)
+{
+       int status;
+       struct fib *cmd_fibcontext;
+       struct aac_power_management *pmcmd;
+       struct scsi_device *sdev = scsicmd->device;
+       struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+
+       if (!(aac->supplement_adapter_info.SupportedOptions2 &
+             AAC_OPTION_POWER_MANAGEMENT)) {
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                                 SAM_STAT_GOOD;
+               scsicmd->scsi_done(scsicmd);
+               return 0;
+       }
+
+       if (aac->in_reset)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       /*
+        *      Allocate and initialize a Fib
+        */
+       cmd_fibcontext = aac_fib_alloc(aac);
+       if (!cmd_fibcontext)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       aac_fib_init(cmd_fibcontext);
+
+       pmcmd = fib_data(cmd_fibcontext);
+       pmcmd->command = cpu_to_le32(VM_ContainerConfig);
+       pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT);
+       /* Eject bit ignored, not relevant */
+       pmcmd->sub = (scsicmd->cmnd[4] & 1) ?
+               cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT);
+       pmcmd->cid = cpu_to_le32(sdev_id(sdev));
+       pmcmd->parm = (scsicmd->cmnd[1] & 1) ?
+               cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0;
+
+       /*
+        *      Now send the Fib to the adapter
+        */
+       status = aac_fib_send(ContainerCommand,
+                 cmd_fibcontext,
+                 sizeof(struct aac_power_management),
+                 FsaNormal,
+                 0, 1,
+                 (fib_callback)aac_start_stop_callback,
+                 (void *)scsicmd);
+
+       /*
+        *      Check that the command queued to the controller
+        */
+       if (status == -EINPROGRESS) {
+               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+               return 0;
+       }
+
+       aac_fib_complete(cmd_fibcontext);
+       aac_fib_free(cmd_fibcontext);
+       return SCSI_MLQUEUE_HOST_BUSY;
+}
+
 /**
  *     aac_scsi_cmd()          -       Process SCSI command
  *     @scsicmd:               SCSI command block
@@ -1887,7 +1997,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                         *      If the target container doesn't exist, it may have
                         *      been newly created
                         */
-                       if ((fsa_dev_ptr[cid].valid & 1) == 0) {
+                       if (((fsa_dev_ptr[cid].valid & 1) == 0) ||
+                         (fsa_dev_ptr[cid].sense_data.sense_key ==
+                          NOT_READY)) {
                                switch (scsicmd->cmnd[0]) {
                                case SERVICE_ACTION_IN:
                                        if (!(dev->raw_io_interface) ||
@@ -1958,8 +2070,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                arr[4] = 0x0;
                                arr[5] = 0x80;
                                arr[1] = scsicmd->cmnd[2];
-                               aac_internal_transfer(scsicmd, &inq_data, 0,
-                                 sizeof(inq_data));
+                               scsi_sg_copy_from_buffer(scsicmd, &inq_data,
+                                                        sizeof(inq_data));
                                scsicmd->result = DID_OK << 16 |
                                  COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
                        } else if (scsicmd->cmnd[2] == 0x80) {
@@ -1967,8 +2079,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                arr[3] = setinqserial(dev, &arr[4],
                                  scmd_id(scsicmd));
                                arr[1] = scsicmd->cmnd[2];
-                               aac_internal_transfer(scsicmd, &inq_data, 0,
-                                 sizeof(inq_data));
+                               scsi_sg_copy_from_buffer(scsicmd, &inq_data,
+                                                        sizeof(inq_data));
                                return aac_get_container_serial(scsicmd);
                        } else {
                                /* vpd page not implemented */
@@ -1999,7 +2111,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                if (cid == host->this_id) {
                        setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types));
                        inq_data.inqd_pdt = INQD_PDT_PROC;      /* Processor device */
-                       aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
+                       scsi_sg_copy_from_buffer(scsicmd, &inq_data,
+                                                sizeof(inq_data));
                        scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
                        scsicmd->scsi_done(scsicmd);
                        return 0;
@@ -2008,7 +2121,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                        return -1;
                setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
                inq_data.inqd_pdt = INQD_PDT_DA;        /* Direct/random access device */
-               aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
+               scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
                return aac_get_container_name(scsicmd);
        }
        case SERVICE_ACTION_IN:
@@ -2019,6 +2132,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
        {
                u64 capacity;
                char cp[13];
+               unsigned int alloc_len;
 
                dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n"));
                capacity = fsa_dev_ptr[cid].size - 1;
@@ -2035,18 +2149,16 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                cp[10] = 2;
                cp[11] = 0;
                cp[12] = 0;
-               aac_internal_transfer(scsicmd, cp, 0,
-                 min_t(size_t, scsicmd->cmnd[13], sizeof(cp)));
-               if (sizeof(cp) < scsicmd->cmnd[13]) {
-                       unsigned int len, offset = sizeof(cp);
 
-                       memset(cp, 0, offset);
-                       do {
-                               len = min_t(size_t, scsicmd->cmnd[13] - offset,
-                                               sizeof(cp));
-                               aac_internal_transfer(scsicmd, cp, offset, len);
-                       } while ((offset += len) < scsicmd->cmnd[13]);
-               }
+               alloc_len = ((scsicmd->cmnd[10] << 24)
+                            + (scsicmd->cmnd[11] << 16)
+                            + (scsicmd->cmnd[12] << 8) + scsicmd->cmnd[13]);
+
+               alloc_len = min_t(size_t, alloc_len, sizeof(cp));
+               scsi_sg_copy_from_buffer(scsicmd, cp, alloc_len);
+               if (alloc_len < scsi_bufflen(scsicmd))
+                       scsi_set_resid(scsicmd,
+                                      scsi_bufflen(scsicmd) - alloc_len);
 
                /* Do not cache partition table for arrays */
                scsicmd->device->removable = 1;
@@ -2076,11 +2188,11 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                cp[5] = 0;
                cp[6] = 2;
                cp[7] = 0;
-               aac_internal_transfer(scsicmd, cp, 0, sizeof(cp));
+               scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp));
                /* Do not cache partition table for arrays */
                scsicmd->device->removable = 1;
-
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                 SAM_STAT_GOOD;
                scsicmd->scsi_done(scsicmd);
 
                return 0;
@@ -2111,7 +2223,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                        if (mode_buf_length > scsicmd->cmnd[4])
                                mode_buf_length = scsicmd->cmnd[4];
                }
-               aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length);
+               scsi_sg_copy_from_buffer(scsicmd, mode_buf, mode_buf_length);
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
                scsicmd->scsi_done(scsicmd);
 
@@ -2146,7 +2258,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                        if (mode_buf_length > scsicmd->cmnd[8])
                                mode_buf_length = scsicmd->cmnd[8];
                }
-               aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length);
+               scsi_sg_copy_from_buffer(scsicmd, mode_buf, mode_buf_length);
 
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
                scsicmd->scsi_done(scsicmd);
@@ -2175,15 +2287,32 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
         *      These commands are all No-Ops
         */
        case TEST_UNIT_READY:
+               if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) {
+                       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                               SAM_STAT_CHECK_CONDITION;
+                       set_sense(&dev->fsa_dev[cid].sense_data,
+                                 NOT_READY, SENCODE_BECOMING_READY,
+                                 ASENCODE_BECOMING_READY, 0, 0);
+                       memcpy(scsicmd->sense_buffer,
+                              &dev->fsa_dev[cid].sense_data,
+                              min_t(size_t,
+                                    sizeof(dev->fsa_dev[cid].sense_data),
+                                    SCSI_SENSE_BUFFERSIZE));
+                       scsicmd->scsi_done(scsicmd);
+                       return 0;
+               }
+               /* FALLTHRU */
        case RESERVE:
        case RELEASE:
        case REZERO_UNIT:
        case REASSIGN_BLOCKS:
        case SEEK_10:
-       case START_STOP:
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
                scsicmd->scsi_done(scsicmd);
                return 0;
+
+       case START_STOP:
+               return aac_start_stop(scsicmd);
        }
 
        switch (scsicmd->cmnd[0])