dma-mapping: replace all DMA_64BIT_MASK macro with DMA_BIT_MASK(64)
[safe/jmp/linux-2.6] / drivers / scsi / aacraid / aachba.c
index b9fc9b1..e83ef8a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *     Adaptec AAC series RAID controller driver
- *     (c) Copyright 2001 Red Hat Inc. <alan@redhat.com>
+ *     (c) Copyright 2001 Red Hat Inc.
  *
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
@@ -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,7 +143,7 @@ static char *aac_get_status_string(u32 status);
  */
 
 static int nondasd = -1;
-static int aac_cache;
+static int aac_cache = 2;      /* WCE=0 to avoid performance problems */
 static int dacmode = -1;
 int aac_msi;
 int aac_commit = -1;
@@ -158,7 +157,7 @@ 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");
+       "\tbit 2 - Disable only if Battery is 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");
@@ -205,7 +204,7 @@ MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health"
 
 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"
+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.");
 
@@ -218,6 +217,14 @@ 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.");
 
+int aac_wwn = 1;
+module_param_named(wwn, aac_wwn, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(wwn, "Select a WWN type for the arrays:\n"
+       "\t0 - Disable\n"
+       "\t1 - Array Meta Data Signature (default)\n"
+       "\t2 - Adapter Serial Number");
+
+
 static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
                struct fib *fibptr) {
        struct scsi_device *device;
@@ -379,24 +386,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;
@@ -419,14 +408,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));
                }
        }
 
@@ -514,6 +506,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)) +
@@ -811,7 +808,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;
@@ -1150,7 +1147,7 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd
        srbcmd->id       = cpu_to_le32(scmd_id(cmd));
        srbcmd->lun      = cpu_to_le32(cmd->device->lun);
        srbcmd->flags    = cpu_to_le32(flag);
-       timeout = cmd->timeout_per_command/HZ;
+       timeout = cmd->request->timeout/HZ;
        if (timeout == 0)
                timeout = 1;
        srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
@@ -1217,9 +1214,8 @@ static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
 
 static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd)
 {
-       if ((sizeof(dma_addr_t) > 4) &&
-        (num_physpages > (0xFFFFFFFFULL >> PAGE_SHIFT)) &&
-        (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64))
+       if ((sizeof(dma_addr_t) > 4) && fib->dev->needs_dac &&
+           (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64))
                return FAILED;
        return aac_scsi_32(fib, cmd);
 }
@@ -1331,7 +1327,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);
@@ -1382,8 +1378,11 @@ int aac_get_adapter_info(struct aac_dev* dev)
        if (dev->nondasd_support && !dev->in_reset)
                printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
 
+       if (dma_get_required_mask(&dev->pdev->dev) > DMA_32BIT_MASK)
+               dev->needs_dac = 1;
        dev->dac_support = 0;
-       if( (sizeof(dma_addr_t) > 4) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){
+       if ((sizeof(dma_addr_t) > 4) && dev->needs_dac &&
+           (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) {
                if (!dev->in_reset)
                        printk(KERN_INFO "%s%d: 64bit support enabled.\n",
                                dev->name, dev->id);
@@ -1393,9 +1392,18 @@ int aac_get_adapter_info(struct aac_dev* dev)
        if(dacmode != -1) {
                dev->dac_support = (dacmode!=0);
        }
+
+       /* avoid problems with AAC_QUIRK_SCSI_32 controllers */
+       if (dev->dac_support && (aac_get_driver_ident(dev->cardtype)->quirks
+               & AAC_QUIRK_SCSI_32)) {
+               dev->nondasd_support = 0;
+               dev->jbod = 0;
+               expose_physicals = 0;
+       }
+
        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)) {
+               if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(64)) &&
+                       !pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(64))) {
                        if (!dev->in_reset)
                                printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n",
                                        dev->name, dev->id);
@@ -1525,20 +1533,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);
@@ -1879,6 +1902,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
@@ -1915,7 +2016,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) ||
@@ -1974,7 +2077,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
                memset(&inq_data, 0, sizeof (struct inquiry_data));
 
-               if (scsicmd->cmnd[1] & 0x1) {
+               if ((scsicmd->cmnd[1] & 0x1) && aac_wwn) {
                        char *arr = (char *)&inq_data;
 
                        /* EVPD bit set */
@@ -1986,8 +2089,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) {
@@ -1995,9 +2098,14 @@ 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));
-                               return aac_get_container_serial(scsicmd);
+                               scsi_sg_copy_from_buffer(scsicmd, &inq_data,
+                                                        sizeof(inq_data));
+                               if (aac_wwn != 2)
+                                       return aac_get_container_serial(
+                                               scsicmd);
+                               /* SLES 10 SP1 special */
+                               scsicmd->result = DID_OK << 16 |
+                                 COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
                        } else {
                                /* vpd page not implemented */
                                scsicmd->result = DID_OK << 16 |
@@ -2027,7 +2135,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;
@@ -2036,7 +2145,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:
@@ -2070,8 +2179,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                             + (scsicmd->cmnd[12] << 8) + scsicmd->cmnd[13]);
 
                alloc_len = min_t(size_t, alloc_len, sizeof(cp));
-               aac_internal_transfer(scsicmd, cp, 0, alloc_len);
-
+               scsi_sg_copy_from_buffer(scsicmd, cp, alloc_len);
                if (alloc_len < scsi_bufflen(scsicmd))
                        scsi_set_resid(scsicmd,
                                       scsi_bufflen(scsicmd) - alloc_len);
@@ -2104,11 +2212,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;
@@ -2139,7 +2247,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);
 
@@ -2174,7 +2282,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);
@@ -2203,15 +2311,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])