fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / scsi / aacraid / aachba.c
index c880115..426cd6f 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/completion.h>
 #include <linux/blkdev.h>
+#include <linux/dma-mapping.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
 
 #define        INQD_PDT_DMASK  0x1F    /* Peripheral Device Type Mask */
 #define        INQD_PDT_QMASK  0xE0    /* Peripheral Device Qualifer Mask */
 
-#define        TARGET_LUN_TO_CONTAINER(target, lun)    (target)
-#define CONTAINER_TO_TARGET(cont)              ((cont))
-#define CONTAINER_TO_LUN(cont)                 (0)
-
-#define MAX_FIB_DATA (sizeof(struct hw_fib) - sizeof(FIB_HEADER))
-
-#define MAX_DRIVER_SG_SEGMENT_COUNT 17
-
-/*
- *     Sense keys
- */
-#define SENKEY_NO_SENSE      0x00      
-#define SENKEY_UNDEFINED     0x01      
-#define SENKEY_NOT_READY     0x02      
-#define SENKEY_MEDIUM_ERR    0x03      
-#define SENKEY_HW_ERR        0x04      
-#define SENKEY_ILLEGAL       0x05      
-#define SENKEY_ATTENTION     0x06      
-#define SENKEY_PROTECTED     0x07      
-#define SENKEY_BLANK         0x08      
-#define SENKEY_V_UNIQUE      0x09      
-#define SENKEY_CPY_ABORT     0x0A      
-#define SENKEY_ABORT         0x0B      
-#define SENKEY_EQUAL         0x0C      
-#define SENKEY_VOL_OVERFLOW  0x0D      
-#define SENKEY_MISCOMP       0x0E      
-#define SENKEY_RESERVED      0x0F      
-
 /*
  *     Sense codes
  */
@@ -155,55 +128,125 @@ struct inquiry_data {
        u8 inqd_prl[4]; /* Product Revision Level */
 };
 
-struct sense_data {
-       u8 error_code;          /* 70h (current errors), 71h(deferred errors) */
-       u8 valid:1;             /* A valid bit of one indicates that the information  */
-                               /* field contains valid information as defined in the
-                                * SCSI-2 Standard.
-                                */
-       u8 segment_number;      /* Only used for COPY, COMPARE, or COPY AND VERIFY Commands */
-       u8 sense_key:4;         /* Sense Key */
-       u8 reserved:1;
-       u8 ILI:1;               /* Incorrect Length Indicator */
-       u8 EOM:1;               /* End Of Medium - reserved for random access devices */
-       u8 filemark:1;          /* Filemark - reserved for random access devices */
-
-       u8 information[4];      /* for direct-access devices, contains the unsigned 
-                                * logical block address or residue associated with 
-                                * the sense key 
-                                */
-       u8 add_sense_len;       /* number of additional sense bytes to follow this field */
-       u8 cmnd_info[4];        /* not used */
-       u8 ASC;                 /* Additional Sense Code */
-       u8 ASCQ;                /* Additional Sense Code Qualifier */
-       u8 FRUC;                /* Field Replaceable Unit Code - not used */
-       u8 bit_ptr:3;           /* indicates which byte of the CDB or parameter data
-                                * was in error
-                                */
-       u8 BPV:1;               /* bit pointer valid (BPV): 1- indicates that 
-                                * the bit_ptr field has valid value
-                                */
-       u8 reserved2:2;
-       u8 CD:1;                /* command data bit: 1- illegal parameter in CDB.
-                                * 0- illegal parameter in data.
-                                */
-       u8 SKSV:1;
-       u8 field_ptr[2];        /* byte of the CDB or parameter data in error */
-};
-
 /*
  *              M O D U L E   G L O B A L S
  */
  
-static struct fsa_scsi_hba *fsa_dev[MAXIMUM_NUM_ADAPTERS];     /*  SCSI Device Instance Pointers */
-static struct sense_data sense_data[MAXIMUM_NUM_CONTAINERS];
 static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);
 static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);
+static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg);
 static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);
 #ifdef AAC_DETAILED_STATUS_INFO
 static char *aac_get_status_string(u32 status);
 #endif
 
+/*
+ *     Non dasd selection is handled entirely in aachba now
+ */    
+static int nondasd = -1;
+static int dacmode = -1;
+
+static int 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_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_param(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_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_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.");
+
+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.");
+
+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.");
+
+int expose_physicals = 0;
+module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. 0=off, 1=on");
+/**
+ *     aac_get_config_status   -       check the adapter configuration
+ *     @common: adapter to query
+ *
+ *     Query config status, and commit the configuration if needed.
+ */
+int aac_get_config_status(struct aac_dev *dev, int commit_flag)
+{
+       int status = 0;
+       struct fib * fibptr;
+
+       if (!(fibptr = aac_fib_alloc(dev)))
+               return -ENOMEM;
+
+       aac_fib_init(fibptr);
+       {
+               struct aac_get_config_status *dinfo;
+               dinfo = (struct aac_get_config_status *) fib_data(fibptr);
+
+               dinfo->command = cpu_to_le32(VM_ContainerConfig);
+               dinfo->type = cpu_to_le32(CT_GET_CONFIG_STATUS);
+               dinfo->count = cpu_to_le32(sizeof(((struct aac_get_config_status_resp *)NULL)->data));
+       }
+
+       status = aac_fib_send(ContainerCommand,
+                           fibptr,
+                           sizeof (struct aac_get_config_status),
+                           FsaNormal,
+                           1, 1,
+                           NULL, NULL);
+       if (status < 0 ) {
+               printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n");
+       } else {
+               struct aac_get_config_status_resp *reply
+                 = (struct aac_get_config_status_resp *) fib_data(fibptr);
+               dprintk((KERN_WARNING
+                 "aac_get_config_status: response=%d status=%d action=%d\n",
+                 le32_to_cpu(reply->response),
+                 le32_to_cpu(reply->status),
+                 le32_to_cpu(reply->data.action)));
+               if ((le32_to_cpu(reply->response) != ST_OK) ||
+                    (le32_to_cpu(reply->status) != CT_OK) ||
+                    (le32_to_cpu(reply->data.action) > CFACT_PAUSE)) {
+                       printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n");
+                       status = -EINVAL;
+               }
+       }
+       aac_fib_complete(fibptr);
+       /* Send a CT_COMMIT_CONFIG to enable discovery of devices */
+       if (status >= 0) {
+               if ((commit == 1) || commit_flag) {
+                       struct aac_commit_config * dinfo;
+                       aac_fib_init(fibptr);
+                       dinfo = (struct aac_commit_config *) fib_data(fibptr);
+       
+                       dinfo->command = cpu_to_le32(VM_ContainerConfig);
+                       dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG);
+       
+                       status = aac_fib_send(ContainerCommand,
+                                   fibptr,
+                                   sizeof (struct aac_commit_config),
+                                   FsaNormal,
+                                   1, 1,
+                                   NULL, NULL);
+                       aac_fib_complete(fibptr);
+               } else if (commit == 0) {
+                       printk(KERN_WARNING
+                         "aac_get_config_status: Foreign device configurations are being ignored\n");
+               }
+       }
+       aac_fib_free(fibptr);
+       return status;
+}
+
 /**
  *     aac_get_containers      -       list containers
  *     @common: adapter to probe
@@ -212,29 +255,64 @@ static char *aac_get_status_string(u32 status);
  */
 int aac_get_containers(struct aac_dev *dev)
 {
-       struct fsa_scsi_hba *fsa_dev_ptr;
+       struct fsa_dev_info *fsa_dev_ptr;
        u32 index; 
        int status = 0;
-       struct aac_query_mount *dinfo;
-       struct aac_mount *dresp;
        struct fib * fibptr;
        unsigned instance;
+       struct aac_get_container_count *dinfo;
+       struct aac_get_container_count_resp *dresp;
+       int maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
 
-       fsa_dev_ptr = &(dev->fsa_dev);
        instance = dev->scsi_host_ptr->unique_id;
 
-       if (!(fibptr = fib_alloc(dev)))
+       if (!(fibptr = aac_fib_alloc(dev)))
+               return -ENOMEM;
+
+       aac_fib_init(fibptr);
+       dinfo = (struct aac_get_container_count *) fib_data(fibptr);
+       dinfo->command = cpu_to_le32(VM_ContainerConfig);
+       dinfo->type = cpu_to_le32(CT_GET_CONTAINER_COUNT);
+
+       status = aac_fib_send(ContainerCommand,
+                   fibptr,
+                   sizeof (struct aac_get_container_count),
+                   FsaNormal,
+                   1, 1,
+                   NULL, NULL);
+       if (status >= 0) {
+               dresp = (struct aac_get_container_count_resp *)fib_data(fibptr);
+               maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
+               aac_fib_complete(fibptr);
+       }
+
+       if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
+               maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
+       fsa_dev_ptr = kmalloc(
+         sizeof(*fsa_dev_ptr) * maximum_num_containers, GFP_KERNEL);
+       if (!fsa_dev_ptr) {
+               aac_fib_free(fibptr);
                return -ENOMEM;
+       }
+       memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers);
 
-       for (index = 0; index < MAXIMUM_NUM_CONTAINERS; index++) {
-               fib_init(fibptr);
+       dev->fsa_dev = fsa_dev_ptr;
+       dev->maximum_num_containers = maximum_num_containers;
+
+       for (index = 0; index < dev->maximum_num_containers; index++) {
+               struct aac_query_mount *dinfo;
+               struct aac_mount *dresp;
+
+               fsa_dev_ptr[index].devname[0] = '\0';
+
+               aac_fib_init(fibptr);
                dinfo = (struct aac_query_mount *) fib_data(fibptr);
 
                dinfo->command = cpu_to_le32(VM_NameServe);
                dinfo->count = cpu_to_le32(index);
                dinfo->type = cpu_to_le32(FT_FILESYS);
 
-               status = fib_send(ContainerCommand,
+               status = aac_fib_send(ContainerCommand,
                                    fibptr,
                                    sizeof (struct aac_query_mount),
                                    FsaNormal,
@@ -246,16 +324,41 @@ int aac_get_containers(struct aac_dev *dev)
                }
                dresp = (struct aac_mount *)fib_data(fibptr);
 
+               if ((le32_to_cpu(dresp->status) == ST_OK) &&
+                   (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
+                       dinfo->command = cpu_to_le32(VM_NameServe64);
+                       dinfo->count = cpu_to_le32(index);
+                       dinfo->type = cpu_to_le32(FT_FILESYS);
+
+                       if (aac_fib_send(ContainerCommand,
+                                   fibptr,
+                                   sizeof(struct aac_query_mount),
+                                   FsaNormal,
+                                   1, 1,
+                                   NULL, NULL) < 0)
+                               continue;
+               } else
+                       dresp->mnt[0].capacityhigh = 0;
+
+               dprintk ((KERN_DEBUG
+                 "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%llu\n",
+                 (int)index, (int)le32_to_cpu(dresp->status),
+                 (int)le32_to_cpu(dresp->mnt[0].vol),
+                 (int)le32_to_cpu(dresp->mnt[0].state),
+                 ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+                   (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32)));
                if ((le32_to_cpu(dresp->status) == ST_OK) &&
                    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
                    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
-                       fsa_dev_ptr->valid[index] = 1;
-                       fsa_dev_ptr->type[index] = le32_to_cpu(dresp->mnt[0].vol);
-                       fsa_dev_ptr->size[index] = le32_to_cpu(dresp->mnt[0].capacity);
+                       fsa_dev_ptr[index].valid = 1;
+                       fsa_dev_ptr[index].type = le32_to_cpu(dresp->mnt[0].vol);
+                       fsa_dev_ptr[index].size
+                         = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+                           (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
                        if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
-                                   fsa_dev_ptr->ro[index] = 1;
+                                   fsa_dev_ptr[index].ro = 1;
                }
-               fib_complete(fibptr);
+               aac_fib_complete(fibptr);
                /*
                 *      If there are no more containers, then stop asking.
                 */
@@ -263,36 +366,141 @@ int aac_get_containers(struct aac_dev *dev)
                        break;
                }
        }
-       fib_free(fibptr);
-       fsa_dev[instance] = fsa_dev_ptr;
+       aac_fib_free(fibptr);
        return status;
 }
 
+static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigned int offset, unsigned int len)
+{
+       void *buf;
+       unsigned int transfer_len;
+       struct scatterlist *sg = scsicmd->request_buffer;
+
+       if (scsicmd->use_sg) {
+               buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+               transfer_len = min(sg->length, len + offset);
+       } else {
+               buf = scsicmd->request_buffer;
+               transfer_len = min(scsicmd->request_bufflen, len + offset);
+       }
+
+       memcpy(buf + offset, data, transfer_len - offset);
+
+       if (scsicmd->use_sg) 
+               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;
+       struct scsi_cmnd * scsicmd;
+
+       scsicmd = (struct scsi_cmnd *) context;
+       scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+       dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
+       BUG_ON(fibptr == NULL);
+
+       get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr);
+       /* Failure is irrelevant, using default value instead */
+       if ((le32_to_cpu(get_name_reply->status) == CT_OK)
+        && (get_name_reply->data[0] != '\0')) {
+               char *sp = get_name_reply->data;
+               sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0';
+               while (*sp == ' ')
+                       ++sp;
+               if (*sp) {
+                       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));
+               }
+       }
+
+       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+
+       aac_fib_complete(fibptr);
+       aac_fib_free(fibptr);
+       scsicmd->scsi_done(scsicmd);
+}
+
+/**
+ *     aac_get_container_name  -       get container name, none blocking.
+ */
+static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
+{
+       int status;
+       struct aac_get_name *dinfo;
+       struct fib * cmd_fibcontext;
+       struct aac_dev * dev;
+
+       dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+
+       if (!(cmd_fibcontext = aac_fib_alloc(dev)))
+               return -ENOMEM;
+
+       aac_fib_init(cmd_fibcontext);
+       dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext);
+
+       dinfo->command = cpu_to_le32(VM_ContainerConfig);
+       dinfo->type = cpu_to_le32(CT_READ_NAME);
+       dinfo->cid = cpu_to_le32(cid);
+       dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
+
+       status = aac_fib_send(ContainerCommand,
+                 cmd_fibcontext, 
+                 sizeof (struct aac_get_name),
+                 FsaNormal, 
+                 0, 1, 
+                 (fib_callback) get_container_name_callback, 
+                 (void *) scsicmd);
+       
+       /*
+        *      Check that the command queued to the controller
+        */
+       if (status == -EINPROGRESS) {
+               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+               return 0;
+       }
+               
+       printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
+       aac_fib_complete(cmd_fibcontext);
+       aac_fib_free(cmd_fibcontext);
+       return -1;
+}
+
 /**
- *     probe_container         -       query a logical volume
+ *     aac_probe_container             -       query a logical volume
  *     @dev: device to query
  *     @cid: container identifier
  *
  *     Queries the controller about the given volume. The volume information
- *     is updated in the struct fsa_scsi_hba structure rather than returned.
+ *     is updated in the struct fsa_dev_info structure rather than returned.
  */
  
-static int probe_container(struct aac_dev *dev, int cid)
+int aac_probe_container(struct aac_dev *dev, int cid)
 {
-       struct fsa_scsi_hba *fsa_dev_ptr;
+       struct fsa_dev_info *fsa_dev_ptr;
        int status;
        struct aac_query_mount *dinfo;
        struct aac_mount *dresp;
        struct fib * fibptr;
        unsigned instance;
 
-       fsa_dev_ptr = &(dev->fsa_dev);
+       fsa_dev_ptr = dev->fsa_dev;
+       if (!fsa_dev_ptr)
+               return -ENOMEM;
        instance = dev->scsi_host_ptr->unique_id;
 
-       if (!(fibptr = fib_alloc(dev)))
+       if (!(fibptr = aac_fib_alloc(dev)))
                return -ENOMEM;
 
-       fib_init(fibptr);
+       aac_fib_init(fibptr);
 
        dinfo = (struct aac_query_mount *)fib_data(fibptr);
 
@@ -300,32 +508,50 @@ static int probe_container(struct aac_dev *dev, int cid)
        dinfo->count = cpu_to_le32(cid);
        dinfo->type = cpu_to_le32(FT_FILESYS);
 
-       status = fib_send(ContainerCommand,
+       status = aac_fib_send(ContainerCommand,
                            fibptr,
                            sizeof(struct aac_query_mount),
                            FsaNormal,
                            1, 1,
                            NULL, NULL);
        if (status < 0) {
-               printk(KERN_WARNING "aacraid: probe_containers query failed.\n");
+               printk(KERN_WARNING "aacraid: aac_probe_container query failed.\n");
                goto error;
        }
 
        dresp = (struct aac_mount *) fib_data(fibptr);
 
+       if ((le32_to_cpu(dresp->status) == ST_OK) &&
+           (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
+               dinfo->command = cpu_to_le32(VM_NameServe64);
+               dinfo->count = cpu_to_le32(cid);
+               dinfo->type = cpu_to_le32(FT_FILESYS);
+
+               if (aac_fib_send(ContainerCommand,
+                           fibptr,
+                           sizeof(struct aac_query_mount),
+                           FsaNormal,
+                           1, 1,
+                           NULL, NULL) < 0)
+                       goto error;
+       } else
+               dresp->mnt[0].capacityhigh = 0;
+
        if ((le32_to_cpu(dresp->status) == ST_OK) &&
            (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
            (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
-               fsa_dev_ptr->valid[cid] = 1;
-               fsa_dev_ptr->type[cid] = le32_to_cpu(dresp->mnt[0].vol);
-               fsa_dev_ptr->size[cid] = le32_to_cpu(dresp->mnt[0].capacity);
+               fsa_dev_ptr[cid].valid = 1;
+               fsa_dev_ptr[cid].type = le32_to_cpu(dresp->mnt[0].vol);
+               fsa_dev_ptr[cid].size
+                 = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+                   (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
                if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
-                       fsa_dev_ptr->ro[cid] = 1;
+                       fsa_dev_ptr[cid].ro = 1;
        }
 
 error:
-       fib_complete(fibptr);
-       fib_free(fibptr);
+       aac_fib_complete(fibptr);
+       aac_fib_free(fibptr);
 
        return status;
 }
@@ -369,6 +595,11 @@ static char *container_types[] = {
         "V-MIRRORS",          
         "PSEUDO R4",          
        "RAID50",
+       "RAID5D",
+       "RAID5D0",
+       "RAID1E",
+       "RAID6",
+       "RAID60",
         "Unknown"
 };
 
@@ -379,38 +610,66 @@ static char *container_types[] = {
  * Arguments: [1] pointer to void [1] int
  *
  * Purpose: Sets SCSI inquiry data strings for vendor, product
- * and revision level. Allows strings to be set in platform dependent
- * files instead of in OS dependent driver source.
+ * and revision level. Allows strings to be set in platform dependant
+ * files instead of in OS dependant driver source.
  */
 
-static void setinqstr(int devtype, void *data, int tindex)
+static void setinqstr(struct aac_dev *dev, void *data, int tindex)
 {
        struct scsi_inq *str;
-       char *findit;
-       struct aac_driver_ident *mp;
 
-       mp = aac_get_driver_ident(devtype);
-   
        str = (struct scsi_inq *)(data); /* cast data to scsi inq block */
+       memset(str, ' ', sizeof(*str));
+
+       if (dev->supplement_adapter_info.AdapterTypeText[0]) {
+               char * cp = dev->supplement_adapter_info.AdapterTypeText;
+               int c = sizeof(str->vid);
+               while (*cp && *cp != ' ' && --c)
+                       ++cp;
+               c = *cp;
+               *cp = '\0';
+               inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
+                 str->vid); 
+               *cp = c;
+               while (*cp && *cp != ' ')
+                       ++cp;
+               while (*cp == ' ')
+                       ++cp;
+               /* last six chars reserved for vol type */
+               c = 0;
+               if (strlen(cp) > sizeof(str->pid)) {
+                       c = cp[sizeof(str->pid)];
+                       cp[sizeof(str->pid)] = '\0';
+               }
+               inqstrcpy (cp, str->pid);
+               if (c)
+                       cp[sizeof(str->pid)] = c;
+       } else {
+               struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype);
 
-       inqstrcpy (mp->vname, str->vid); 
-       inqstrcpy (mp->model, str->pid); /* last six chars reserved for vol type */
+               inqstrcpy (mp->vname, str->vid);
+               /* last six chars reserved for vol type */
+               inqstrcpy (mp->model, str->pid);
+       }
 
-       findit = str->pid;
+       if (tindex < ARRAY_SIZE(container_types)){
+               char *findit = str->pid;
 
-       for ( ; *findit != ' '; findit++); /* walk till we find a space then incr by 1 */
-               findit++;
-       
-       if (tindex < (sizeof(container_types)/sizeof(char *))){
-               inqstrcpy (container_types[tindex], findit);
+               for ( ; *findit != ' '; findit++); /* walk till we find a space */
+               /* RAID is superfluous in the context of a RAID device */
+               if (memcmp(findit-4, "RAID", 4) == 0)
+                       *(findit -= 4) = ' ';
+               if (((findit - str->pid) + strlen(container_types[tindex]))
+                < (sizeof(str->pid) + sizeof(str->prl)))
+                       inqstrcpy (container_types[tindex], findit + 1);
        }
        inqstrcpy ("V1.0", str->prl);
 }
 
-void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
-                   u8 a_sense_code, u8 incorrect_length,
-                   u8 bit_pointer, u16 field_pointer,
-                   u32 residue)
+static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
+                     u8 a_sense_code, u8 incorrect_length,
+                     u8 bit_pointer, u16 field_pointer,
+                     u32 residue)
 {
        sense_buf[0] = 0xF0;    /* Sense data valid, err code 70h (current error) */
        sense_buf[1] = 0;       /* Segment number, always zero */
@@ -424,14 +683,14 @@ void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
        } else
                sense_buf[2] = sense_key;       /* Sense key */
 
-       if (sense_key == SENKEY_ILLEGAL)
+       if (sense_key == ILLEGAL_REQUEST)
                sense_buf[7] = 10;      /* Additional sense length */
        else
                sense_buf[7] = 6;       /* Additional sense length */
 
        sense_buf[12] = sense_code;     /* Additional sense code */
        sense_buf[13] = a_sense_code;   /* Additional sense code qualifier */
-       if (sense_key == SENKEY_ILLEGAL) {
+       if (sense_key == ILLEGAL_REQUEST) {
                sense_buf[15] = 0;
 
                if (sense_code == SENCODE_INVALID_PARAM_FIELD)
@@ -447,190 +706,302 @@ void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
        }
 }
 
-static void aac_io_done(struct scsi_cmnd * scsicmd)
-{
-       unsigned long cpu_flags;
-       struct Scsi_Host *host = scsicmd->device->host;
-       spin_lock_irqsave(host->host_lock, cpu_flags);
-       scsicmd->scsi_done(scsicmd);
-       spin_unlock_irqrestore(host->host_lock, cpu_flags);
-}
-
-static void __aac_io_done(struct scsi_cmnd * scsicmd)
-{
-       scsicmd->scsi_done(scsicmd);
-}
-
 int aac_get_adapter_info(struct aac_dev* dev)
 {
        struct fib* fibptr;
-       struct aac_adapter_info* info;
        int rcode;
        u32 tmp;
-       if (!(fibptr = fib_alloc(dev)))
+       struct aac_adapter_info *info;
+       struct aac_bus_info *command;
+       struct aac_bus_info_response *bus_info;
+
+       if (!(fibptr = aac_fib_alloc(dev)))
                return -ENOMEM;
 
-       fib_init(fibptr);
-       info = (struct aac_adapter_info*) fib_data(fibptr);
+       aac_fib_init(fibptr);
+       info = (struct aac_adapter_info *) fib_data(fibptr);
+       memset(info,0,sizeof(*info));
+
+       rcode = aac_fib_send(RequestAdapterInfo,
+                        fibptr, 
+                        sizeof(*info),
+                        FsaNormal, 
+                        -1, 1, /* First `interrupt' command uses special wait */
+                        NULL, 
+                        NULL);
+
+       if (rcode < 0) {
+               aac_fib_complete(fibptr);
+               aac_fib_free(fibptr);
+               return rcode;
+       }
+       memcpy(&dev->adapter_info, info, sizeof(*info));
 
-       memset(info,0,sizeof(struct aac_adapter_info));
+       if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) {
+               struct aac_supplement_adapter_info * info;
 
-       rcode = fib_send(RequestAdapterInfo,
-                       fibptr, 
-                       sizeof(struct aac_adapter_info),
-                       FsaNormal, 
-                       1, 1, 
-                       NULL, 
-                       NULL);
+               aac_fib_init(fibptr);
 
-       memcpy(&dev->adapter_info, info, sizeof(struct aac_adapter_info));
+               info = (struct aac_supplement_adapter_info *) fib_data(fibptr);
 
-       tmp = dev->adapter_info.kernelrev;
-       printk(KERN_INFO"%s%d: kernel %d.%d.%d build %d\n", 
-                       dev->name, dev->id,
-                       tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
-                       dev->adapter_info.kernelbuild);
-       tmp = dev->adapter_info.monitorrev;
-       printk(KERN_INFO"%s%d: monitor %d.%d.%d build %d\n", 
-                       dev->name, dev->id,
-                       tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
-                       dev->adapter_info.monitorbuild);
-       tmp = dev->adapter_info.biosrev;
-       printk(KERN_INFO"%s%d: bios %d.%d.%d build %d\n", 
+               memset(info,0,sizeof(*info));
+
+               rcode = aac_fib_send(RequestSupplementAdapterInfo,
+                                fibptr,
+                                sizeof(*info),
+                                FsaNormal,
+                                1, 1,
+                                NULL,
+                                NULL);
+
+               if (rcode >= 0)
+                       memcpy(&dev->supplement_adapter_info, info, sizeof(*info));
+       }
+
+
+       /* 
+        * GetBusInfo 
+        */
+
+       aac_fib_init(fibptr);
+
+       bus_info = (struct aac_bus_info_response *) fib_data(fibptr);
+
+       memset(bus_info, 0, sizeof(*bus_info));
+
+       command = (struct aac_bus_info *)bus_info;
+
+       command->Command = cpu_to_le32(VM_Ioctl);
+       command->ObjType = cpu_to_le32(FT_DRIVE);
+       command->MethodId = cpu_to_le32(1);
+       command->CtlCmd = cpu_to_le32(GetBusInfo);
+
+       rcode = aac_fib_send(ContainerCommand,
+                        fibptr,
+                        sizeof (*bus_info),
+                        FsaNormal,
+                        1, 1,
+                        NULL, NULL);
+
+       if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) {
+               dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus);
+               dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
+       }
+
+       if (!dev->in_reset) {
+               tmp = le32_to_cpu(dev->adapter_info.kernelrev);
+               printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
+                       dev->name, 
+                       dev->id,
+                       tmp>>24,
+                       (tmp>>16)&0xff,
+                       tmp&0xff,
+                       le32_to_cpu(dev->adapter_info.kernelbuild),
+                       (int)sizeof(dev->supplement_adapter_info.BuildDate),
+                       dev->supplement_adapter_info.BuildDate);
+               tmp = le32_to_cpu(dev->adapter_info.monitorrev);
+               printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
                        dev->name, dev->id,
-                       tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
-                       dev->adapter_info.biosbuild);
-       printk(KERN_INFO"%s%d: serial %x%x\n",
+                       tmp>>24,(tmp>>16)&0xff,tmp&0xff,
+                       le32_to_cpu(dev->adapter_info.monitorbuild));
+               tmp = le32_to_cpu(dev->adapter_info.biosrev);
+               printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
                        dev->name, dev->id,
-                       dev->adapter_info.serial[0],
-                       dev->adapter_info.serial[1]);
+                       tmp>>24,(tmp>>16)&0xff,tmp&0xff,
+                       le32_to_cpu(dev->adapter_info.biosbuild));
+               if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
+                       printk(KERN_INFO "%s%d: serial %x\n",
+                               dev->name, dev->id,
+                               le32_to_cpu(dev->adapter_info.serial[0]));
+       }
 
        dev->nondasd_support = 0;
+       dev->raid_scsi_mode = 0;
        if(dev->adapter_info.options & AAC_OPT_NONDASD){
-//             dev->nondasd_support = 1;
-// dmb - temporarily disable nondasd
+               dev->nondasd_support = 1;
+       }
+
+       /*
+        * If the firmware supports ROMB RAID/SCSI mode and we are currently
+        * in RAID/SCSI mode, set the flag. For now if in this mode we will
+        * force nondasd support on. If we decide to allow the non-dasd flag
+        * additional changes changes will have to be made to support
+        * RAID/SCSI.  the function aac_scsi_cmd in this module will have to be
+        * changed to support the new dev->raid_scsi_mode flag instead of
+        * leaching off of the dev->nondasd_support flag. Also in linit.c the
+        * function aac_detect will have to be modified where it sets up the
+        * max number of channels based on the aac->nondasd_support flag only.
+        */
+       if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED) &&
+           (dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE)) {
+               dev->nondasd_support = 1;
+               dev->raid_scsi_mode = 1;
        }
+       if (dev->raid_scsi_mode != 0)
+               printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",
+                               dev->name, dev->id);
+               
        if(nondasd != -1) {  
                dev->nondasd_support = (nondasd!=0);
        }
        if(dev->nondasd_support != 0){
-               printk(KERN_INFO"%s%d: Non-DASD support enabled\n",dev->name, dev->id);
+               printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
        }
 
-       dev->pae_support = 0;
+       dev->dac_support = 0;
        if( (sizeof(dma_addr_t) > 4) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){
-               dev->pae_support = 1;
+               printk(KERN_INFO "%s%d: 64bit support enabled.\n", dev->name, dev->id);
+               dev->dac_support = 1;
        }
 
-       if(paemode != -1){
-               dev->pae_support = (paemode!=0);
+       if(dacmode != -1) {
+               dev->dac_support = (dacmode!=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)) {
+                       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",
+                               dev->name, dev->id);
+                       dev->dac_support = 0;
+               } else {
+                       printk(KERN_WARNING"%s%d: No suitable DMA available.\n",
+                               dev->name, dev->id);
+                       rcode = -ENOMEM;
+               }
        }
-       if(dev->pae_support != 0) {
-               printk(KERN_INFO"%s%d: 64 Bit PAE enabled\n", dev->name, dev->id);
-               pci_set_dma_mask(dev->pdev, (dma_addr_t)0xFFFFFFFFFFFFFFFFULL);
+       /* 
+        * 57 scatter gather elements 
+        */
+       if (!(dev->raw_io_interface)) {
+               dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size -
+                       sizeof(struct aac_fibhdr) -
+                       sizeof(struct aac_write) + sizeof(struct sgentry)) /
+                               sizeof(struct sgentry);
+               if (dev->dac_support) {
+                       /* 
+                        * 38 scatter gather elements 
+                        */
+                       dev->scsi_host_ptr->sg_tablesize =
+                               (dev->max_fib_size -
+                               sizeof(struct aac_fibhdr) -
+                               sizeof(struct aac_write64) +
+                               sizeof(struct sgentry64)) /
+                                       sizeof(struct sgentry64);
+               }
+               dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
+               if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
+                       /*
+                        * Worst case size that could cause sg overflow when
+                        * we break up SG elements that are larger than 64KB.
+                        * Would be nice if we could tell the SCSI layer what
+                        * the maximum SG element size can be. Worst case is
+                        * (sg_tablesize-1) 4KB elements with one 64KB
+                        * element.
+                        *      32bit -> 468 or 238KB   64bit -> 424 or 212KB
+                        */
+                       dev->scsi_host_ptr->max_sectors =
+                         (dev->scsi_host_ptr->sg_tablesize * 8) + 112;
+               }
        }
 
-       fib_complete(fibptr);
-       fib_free(fibptr);
+       aac_fib_complete(fibptr);
+       aac_fib_free(fibptr);
 
        return rcode;
 }
 
 
-static void read_callback(void *context, struct fib * fibptr)
+static void io_callback(void *context, struct fib * fibptr)
 {
        struct aac_dev *dev;
        struct aac_read_reply *readreply;
        struct scsi_cmnd *scsicmd;
-       u32 lba;
        u32 cid;
 
        scsicmd = (struct scsi_cmnd *) context;
+       scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
 
        dev = (struct aac_dev *)scsicmd->device->host->hostdata;
-       cid =TARGET_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
+       cid = scmd_id(scsicmd);
 
-       lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
-       dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
+       if (nblank(dprintk(x))) {
+               u64 lba;
+               switch (scsicmd->cmnd[0]) {
+               case WRITE_6:
+               case READ_6:
+                       lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
+                           (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+                       break;
+               case WRITE_16:
+               case READ_16:
+                       lba = ((u64)scsicmd->cmnd[2] << 56) |
+                             ((u64)scsicmd->cmnd[3] << 48) |
+                             ((u64)scsicmd->cmnd[4] << 40) |
+                             ((u64)scsicmd->cmnd[5] << 32) |
+                             ((u64)scsicmd->cmnd[6] << 24) |
+                             (scsicmd->cmnd[7] << 16) |
+                             (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+                       break;
+               case WRITE_12:
+               case READ_12:
+                       lba = ((u64)scsicmd->cmnd[2] << 24) |
+                             (scsicmd->cmnd[3] << 16) |
+                             (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+                       break;
+               default:
+                       lba = ((u64)scsicmd->cmnd[2] << 24) |
+                              (scsicmd->cmnd[3] << 16) |
+                              (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+                       break;
+               }
+               printk(KERN_DEBUG
+                 "io_callback[cpu %d]: lba = %llu, t = %ld.\n",
+                 smp_processor_id(), (unsigned long long)lba, jiffies);
+       }
 
-       if (fibptr == NULL)
-               BUG();
+       BUG_ON(fibptr == NULL);
                
        if(scsicmd->use_sg)
                pci_unmap_sg(dev->pdev, 
-                       (struct scatterlist *)scsicmd->buffer,
+                       (struct scatterlist *)scsicmd->request_buffer,
                        scsicmd->use_sg,
                        scsicmd->sc_data_direction);
        else if(scsicmd->request_bufflen)
-               pci_unmap_single(dev->pdev, (dma_addr_t)(ulong)scsicmd->SCp.ptr,
+               pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle,
                                 scsicmd->request_bufflen,
                                 scsicmd->sc_data_direction);
        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 {
-               printk(KERN_WARNING "read_callback: read failed, status = %d\n", readreply->status);
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
-               set_sense((u8 *) &sense_data[cid],
-                                   SENKEY_HW_ERR,
-                                   SENCODE_INTERNAL_TARGET_FAILURE,
-                                   ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
-                                   0, 0);
-       }
-       fib_complete(fibptr);
-       fib_free(fibptr);
-
-       aac_io_done(scsicmd);
-}
-
-static void write_callback(void *context, struct fib * fibptr)
-{
-       struct aac_dev *dev;
-       struct aac_write_reply *writereply;
-       struct scsi_cmnd *scsicmd;
-       u32 lba;
-       u32 cid;
-
-       scsicmd = (struct scsi_cmnd *) context;
-       dev = (struct aac_dev *)scsicmd->device->host->hostdata;
-       cid = TARGET_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
-
-       lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
-       dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
-       if (fibptr == NULL)
-               BUG();
-
-       if(scsicmd->use_sg)
-               pci_unmap_sg(dev->pdev, 
-                       (struct scatterlist *)scsicmd->buffer,
-                       scsicmd->use_sg,
-                       scsicmd->sc_data_direction);
-       else if(scsicmd->request_bufflen)
-               pci_unmap_single(dev->pdev, (dma_addr_t)(ulong)scsicmd->SCp.ptr,
-                                scsicmd->request_bufflen,
-                                scsicmd->sc_data_direction);
-
-       writereply = (struct aac_write_reply *) fib_data(fibptr);
-       if (le32_to_cpu(writereply->status) == ST_OK)
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-       else {
-               printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status);
+#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;
-               set_sense((u8 *) &sense_data[cid],
-                                   SENKEY_HW_ERR,
+               set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+                                   HARDWARE_ERROR,
                                    SENCODE_INTERNAL_TARGET_FAILURE,
                                    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
                                    0, 0);
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                 (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+                   ? sizeof(scsicmd->sense_buffer)
+                   : sizeof(dev->fsa_dev[cid].sense_data));
        }
+       aac_fib_complete(fibptr);
+       aac_fib_free(fibptr);
 
-       fib_complete(fibptr);
-       fib_free(fibptr);
-       aac_io_done(scsicmd);
+       scsicmd->scsi_done(scsicmd);
 }
 
-int aac_read(struct scsi_cmnd * scsicmd, int cid)
+static int aac_read(struct scsi_cmnd * scsicmd, int cid)
 {
-       u32 lba;
+       u64 lba;
        u32 count;
        int status;
 
@@ -642,81 +1013,151 @@ int aac_read(struct scsi_cmnd * scsicmd, int cid)
        /*
         *      Get block address and transfer length
         */
-       if (scsicmd->cmnd[0] == READ_6) /* 6 byte command */
-       {
-               dprintk((KERN_DEBUG "aachba: received a read(6) command on target %d.\n", cid));
+       switch (scsicmd->cmnd[0]) {
+       case READ_6:
+               dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", cid));
 
-               lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+               lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | 
+                       (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
                count = scsicmd->cmnd[4];
 
                if (count == 0)
                        count = 256;
-       } else {
-               dprintk((KERN_DEBUG "aachba: received a read(10) command on target %d.\n", cid));
+               break;
+       case READ_16:
+               dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", cid));
+
+               lba =   ((u64)scsicmd->cmnd[2] << 56) |
+                       ((u64)scsicmd->cmnd[3] << 48) |
+                       ((u64)scsicmd->cmnd[4] << 40) |
+                       ((u64)scsicmd->cmnd[5] << 32) |
+                       ((u64)scsicmd->cmnd[6] << 24) | 
+                       (scsicmd->cmnd[7] << 16) |
+                       (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+               count = (scsicmd->cmnd[10] << 24) | 
+                       (scsicmd->cmnd[11] << 16) |
+                       (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
+               break;
+       case READ_12:
+               dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", cid));
+
+               lba = ((u64)scsicmd->cmnd[2] << 24) | 
+                       (scsicmd->cmnd[3] << 16) |
+                       (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+               count = (scsicmd->cmnd[6] << 24) | 
+                       (scsicmd->cmnd[7] << 16) |
+                       (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+               break;
+       default:
+               dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", cid));
 
-               lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+               lba = ((u64)scsicmd->cmnd[2] << 24) | 
+                       (scsicmd->cmnd[3] << 16) | 
+                       (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
                count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
+               break;
+       }
+       dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
+         smp_processor_id(), (unsigned long long)lba, jiffies));
+       if ((!(dev->raw_io_interface) || !(dev->raw_io_64)) &&
+               (lba & 0xffffffff00000000LL)) {
+               dprintk((KERN_DEBUG "aac_read: Illegal lba\n"));
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 
+                       SAM_STAT_CHECK_CONDITION;
+               set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+                           HARDWARE_ERROR,
+                           SENCODE_INTERNAL_TARGET_FAILURE,
+                           ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+                           0, 0);
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                 (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+                   ? sizeof(scsicmd->sense_buffer)
+                   : sizeof(dev->fsa_dev[cid].sense_data));
+               scsicmd->scsi_done(scsicmd);
+               return 0;
        }
-       dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
        /*
         *      Alocate and initialize a Fib
         */
-       if (!(cmd_fibcontext = fib_alloc(dev))) {
-               scsicmd->result = DID_ERROR << 16;
-               aac_io_done(scsicmd);
-               return (-1);
+       if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
+               return -1;
        }
 
-       fib_init(cmd_fibcontext);
+       aac_fib_init(cmd_fibcontext);
 
-       if(dev->pae_support == 1){
+       if (dev->raw_io_interface) {
+               struct aac_raw_io *readcmd;
+               readcmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
+               readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
+               readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
+               readcmd->count = cpu_to_le32(count<<9);
+               readcmd->cid = cpu_to_le16(cid);
+               readcmd->flags = cpu_to_le16(1);
+               readcmd->bpTotal = 0;
+               readcmd->bpComplete = 0;
+               
+               aac_build_sgraw(scsicmd, &readcmd->sg);
+               fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw));
+               BUG_ON(fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)));
+               /*
+                *      Now send the Fib to the adapter
+                */
+               status = aac_fib_send(ContainerRawIo,
+                         cmd_fibcontext, 
+                         fibsize, 
+                         FsaNormal, 
+                         0, 1, 
+                         (fib_callback) io_callback, 
+                         (void *) scsicmd);
+       } else if (dev->dac_support == 1) {
                struct aac_read64 *readcmd;
                readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext);
                readcmd->command = cpu_to_le32(VM_CtHostRead64);
                readcmd->cid = cpu_to_le16(cid);
                readcmd->sector_count = cpu_to_le16(count);
-               readcmd->block = cpu_to_le32(lba);
-               readcmd->pad   = cpu_to_le16(0);
-               readcmd->flags = cpu_to_le16(0)
+               readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
+               readcmd->pad   = 0;
+               readcmd->flags = 0
 
                aac_build_sg64(scsicmd, &readcmd->sg);
-               if(readcmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
-                       BUG();
-               fibsize = sizeof(struct aac_read64) + ((readcmd->sg.count - 1) * sizeof (struct sgentry64));
+               fibsize = sizeof(struct aac_read64) + 
+                       ((le32_to_cpu(readcmd->sg.count) - 1) * 
+                        sizeof (struct sgentry64));
+               BUG_ON (fibsize > (dev->max_fib_size - 
+                                       sizeof(struct aac_fibhdr)));
                /*
                 *      Now send the Fib to the adapter
                 */
-               status = fib_send(ContainerCommand64, 
+               status = aac_fib_send(ContainerCommand64,
                          cmd_fibcontext, 
                          fibsize, 
                          FsaNormal, 
                          0, 1, 
-                         (fib_callback) read_callback, 
+                         (fib_callback) io_callback, 
                          (void *) scsicmd);
        } else {
                struct aac_read *readcmd;
                readcmd = (struct aac_read *) fib_data(cmd_fibcontext);
                readcmd->command = cpu_to_le32(VM_CtBlockRead);
                readcmd->cid = cpu_to_le32(cid);
-               readcmd->block = cpu_to_le32(lba);
+               readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
                readcmd->count = cpu_to_le32(count * 512);
 
-               if (count * 512 > (64 * 1024))
-                       BUG();
-
                aac_build_sg(scsicmd, &readcmd->sg);
-               if(readcmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
-                       BUG();
-               fibsize = sizeof(struct aac_read) + ((readcmd->sg.count - 1) * sizeof (struct sgentry));
+               fibsize = sizeof(struct aac_read) + 
+                       ((le32_to_cpu(readcmd->sg.count) - 1) * 
+                        sizeof (struct sgentry));
+               BUG_ON (fibsize > (dev->max_fib_size -
+                                       sizeof(struct aac_fibhdr)));
                /*
                 *      Now send the Fib to the adapter
                 */
-               status = fib_send(ContainerCommand, 
+               status = aac_fib_send(ContainerCommand,
                          cmd_fibcontext, 
                          fibsize, 
                          FsaNormal, 
                          0, 1, 
-                         (fib_callback) read_callback, 
+                         (fib_callback) io_callback, 
                          (void *) scsicmd);
        }
 
@@ -725,23 +1166,25 @@ int aac_read(struct scsi_cmnd * scsicmd, int cid)
        /*
         *      Check that the command queued to the controller
         */
-       if (status == -EINPROGRESS) 
+       if (status == -EINPROGRESS) {
+               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
                return 0;
+       }
                
-       printk(KERN_WARNING "aac_read: fib_send failed with status: %d.\n", status);
+       printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
        /*
         *      For some reason, the Fib didn't queue, return QUEUE_FULL
         */
        scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
-       aac_io_done(scsicmd);
-       fib_complete(cmd_fibcontext);
-       fib_free(cmd_fibcontext);
-       return -1;
+       scsicmd->scsi_done(scsicmd);
+       aac_fib_complete(cmd_fibcontext);
+       aac_fib_free(cmd_fibcontext);
+       return 0;
 }
 
 static int aac_write(struct scsi_cmnd * scsicmd, int cid)
 {
-       u32 lba;
+       u64 lba;
        u32 count;
        int status;
        u16 fibsize;
@@ -758,99 +1201,275 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
                count = scsicmd->cmnd[4];
                if (count == 0)
                        count = 256;
+       } else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
+               dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", cid));
+
+               lba =   ((u64)scsicmd->cmnd[2] << 56) |
+                       ((u64)scsicmd->cmnd[3] << 48) |
+                       ((u64)scsicmd->cmnd[4] << 40) |
+                       ((u64)scsicmd->cmnd[5] << 32) |
+                       ((u64)scsicmd->cmnd[6] << 24) | 
+                       (scsicmd->cmnd[7] << 16) |
+                       (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+               count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
+                       (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
+       } else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
+               dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", cid));
+
+               lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16)
+                   | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+               count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
+                     | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
        } else {
-               dprintk((KERN_DEBUG "aachba: received a write(10) command on target %d.\n", cid));
-               lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+               dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", cid));
+               lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
                count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
        }
-       dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
+       dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
+         smp_processor_id(), (unsigned long long)lba, jiffies));
+       if ((!(dev->raw_io_interface) || !(dev->raw_io_64))
+        && (lba & 0xffffffff00000000LL)) {
+               dprintk((KERN_DEBUG "aac_write: Illegal lba\n"));
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+               set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+                           HARDWARE_ERROR,
+                           SENCODE_INTERNAL_TARGET_FAILURE,
+                           ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+                           0, 0);
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                 (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+                   ? sizeof(scsicmd->sense_buffer)
+                   : sizeof(dev->fsa_dev[cid].sense_data));
+               scsicmd->scsi_done(scsicmd);
+               return 0;
+       }
        /*
         *      Allocate and initialize a Fib then setup a BlockWrite command
         */
-       if (!(cmd_fibcontext = fib_alloc(dev))) {
+       if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
                scsicmd->result = DID_ERROR << 16;
-               aac_io_done(scsicmd);
-               return -1;
+               scsicmd->scsi_done(scsicmd);
+               return 0;
        }
-       fib_init(cmd_fibcontext);
-
-       if(dev->pae_support == 1){
+       aac_fib_init(cmd_fibcontext);
+
+       if (dev->raw_io_interface) {
+               struct aac_raw_io *writecmd;
+               writecmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
+               writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
+               writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
+               writecmd->count = cpu_to_le32(count<<9);
+               writecmd->cid = cpu_to_le16(cid);
+               writecmd->flags = 0; 
+               writecmd->bpTotal = 0;
+               writecmd->bpComplete = 0;
+               
+               aac_build_sgraw(scsicmd, &writecmd->sg);
+               fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw));
+               BUG_ON(fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)));
+               /*
+                *      Now send the Fib to the adapter
+                */
+               status = aac_fib_send(ContainerRawIo,
+                         cmd_fibcontext, 
+                         fibsize, 
+                         FsaNormal, 
+                         0, 1, 
+                         (fib_callback) io_callback, 
+                         (void *) scsicmd);
+       } else if (dev->dac_support == 1) {
                struct aac_write64 *writecmd;
                writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext);
                writecmd->command = cpu_to_le32(VM_CtHostWrite64);
                writecmd->cid = cpu_to_le16(cid);
                writecmd->sector_count = cpu_to_le16(count); 
-               writecmd->block = cpu_to_le32(lba);
-               writecmd->pad   = cpu_to_le16(0);
-               writecmd->flags = cpu_to_le16(0);
+               writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
+               writecmd->pad   = 0;
+               writecmd->flags = 0;
 
                aac_build_sg64(scsicmd, &writecmd->sg);
-               if(writecmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
-                       BUG();
-               fibsize = sizeof(struct aac_write64) + ((writecmd->sg.count - 1) * sizeof (struct sgentry64));
+               fibsize = sizeof(struct aac_write64) + 
+                       ((le32_to_cpu(writecmd->sg.count) - 1) * 
+                        sizeof (struct sgentry64));
+               BUG_ON (fibsize > (dev->max_fib_size -
+                                       sizeof(struct aac_fibhdr)));
                /*
                 *      Now send the Fib to the adapter
                 */
-               status = fib_send(ContainerCommand64, 
+               status = aac_fib_send(ContainerCommand64,
                          cmd_fibcontext, 
                          fibsize, 
                          FsaNormal, 
                          0, 1, 
-                         (fib_callback) write_callback, 
+                         (fib_callback) io_callback, 
                          (void *) scsicmd);
        } else {
                struct aac_write *writecmd;
                writecmd = (struct aac_write *) fib_data(cmd_fibcontext);
                writecmd->command = cpu_to_le32(VM_CtBlockWrite);
                writecmd->cid = cpu_to_le32(cid);
-               writecmd->block = cpu_to_le32(lba);
+               writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
                writecmd->count = cpu_to_le32(count * 512);
                writecmd->sg.count = cpu_to_le32(1);
                /* ->stable is not used - it did mean which type of write */
 
-               if (count * 512 > (64 * 1024)) {
-                       BUG();
-               }
-
                aac_build_sg(scsicmd, &writecmd->sg);
-               if(writecmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
-                       BUG();
-               fibsize = sizeof(struct aac_write) + ((writecmd->sg.count - 1) * sizeof (struct sgentry));
+               fibsize = sizeof(struct aac_write) + 
+                       ((le32_to_cpu(writecmd->sg.count) - 1) * 
+                        sizeof (struct sgentry));
+               BUG_ON (fibsize > (dev->max_fib_size -
+                                       sizeof(struct aac_fibhdr)));
                /*
                 *      Now send the Fib to the adapter
                 */
-               status = fib_send(ContainerCommand, 
+               status = aac_fib_send(ContainerCommand,
                          cmd_fibcontext, 
                          fibsize, 
                          FsaNormal, 
                          0, 1, 
-                         (fib_callback) write_callback, 
+                         (fib_callback) io_callback, 
                          (void *) scsicmd);
        }
 
        /*
         *      Check that the command queued to the controller
         */
-       if (status == -EINPROGRESS)
+       if (status == -EINPROGRESS) {
+               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
                return 0;
+       }
 
-       printk(KERN_WARNING "aac_write: fib_send failed with status: %d\n", status);
+       printk(KERN_WARNING "aac_write: aac_fib_send failed with status: %d\n", status);
        /*
         *      For some reason, the Fib didn't queue, return QUEUE_FULL
         */
        scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
-       aac_io_done(scsicmd);
+       scsicmd->scsi_done(scsicmd);
 
-       fib_complete(cmd_fibcontext);
-       fib_free(cmd_fibcontext);
-       return -1;
+       aac_fib_complete(cmd_fibcontext);
+       aac_fib_free(cmd_fibcontext);
+       return 0;
+}
+
+static void synchronize_callback(void *context, struct fib *fibptr)
+{
+       struct aac_synchronize_reply *synchronizereply;
+       struct scsi_cmnd *cmd;
+
+       cmd = context;
+       cmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+       dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", 
+                               smp_processor_id(), jiffies));
+       BUG_ON(fibptr == NULL);
+
+
+       synchronizereply = fib_data(fibptr);
+       if (le32_to_cpu(synchronizereply->status) == CT_OK)
+               cmd->result = DID_OK << 16 | 
+                       COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+       else {
+               struct scsi_device *sdev = cmd->device;
+               struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+               u32 cid = sdev_id(sdev);
+               printk(KERN_WARNING 
+                    "synchronize_callback: synchronize failed, status = %d\n",
+                    le32_to_cpu(synchronizereply->status));
+               cmd->result = DID_OK << 16 | 
+                       COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+               set_sense((u8 *)&dev->fsa_dev[cid].sense_data,
+                                   HARDWARE_ERROR,
+                                   SENCODE_INTERNAL_TARGET_FAILURE,
+                                   ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+                                   0, 0);
+               memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                 min(sizeof(dev->fsa_dev[cid].sense_data), 
+                         sizeof(cmd->sense_buffer)));
+       }
+
+       aac_fib_complete(fibptr);
+       aac_fib_free(fibptr);
+       cmd->scsi_done(cmd);
 }
 
+static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
+{
+       int status;
+       struct fib *cmd_fibcontext;
+       struct aac_synchronize *synchronizecmd;
+       struct scsi_cmnd *cmd;
+       struct scsi_device *sdev = scsicmd->device;
+       int active = 0;
+       struct aac_dev *aac;
+       unsigned long flags;
+
+       /*
+        * Wait for all outstanding queued commands to complete to this
+        * specific target (block).
+        */
+       spin_lock_irqsave(&sdev->list_lock, flags);
+       list_for_each_entry(cmd, &sdev->cmd_list, list)
+               if (cmd != scsicmd && cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
+                       ++active;
+                       break;
+               }
+
+       spin_unlock_irqrestore(&sdev->list_lock, flags);
+
+       /*
+        *      Yield the processor (requeue for later)
+        */
+       if (active)
+               return SCSI_MLQUEUE_DEVICE_BUSY;
+
+       aac = (struct aac_dev *)scsicmd->device->host->hostdata;
+       if (aac->in_reset)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       /*
+        *      Allocate and initialize a Fib
+        */
+       if (!(cmd_fibcontext = aac_fib_alloc(aac)))
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       aac_fib_init(cmd_fibcontext);
+
+       synchronizecmd = fib_data(cmd_fibcontext);
+       synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
+       synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
+       synchronizecmd->cid = cpu_to_le32(cid);
+       synchronizecmd->count = 
+            cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
+
+       /*
+        *      Now send the Fib to the adapter
+        */
+       status = aac_fib_send(ContainerCommand,
+                 cmd_fibcontext,
+                 sizeof(struct aac_synchronize),
+                 FsaNormal,
+                 0, 1,
+                 (fib_callback)synchronize_callback,
+                 (void *)scsicmd);
+
+       /*
+        *      Check that the command queued to the controller
+        */
+       if (status == -EINPROGRESS) {
+               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+               return 0;
+       }
+
+       printk(KERN_WARNING 
+               "aac_synchronize: aac_fib_send failed with status: %d.\n", status);
+       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
- *     @wait:                  1 if the user wants to await completion
  *
  *     Emulate a SCSI command and queue the required request for the
  *     aacraid firmware.
@@ -859,45 +1478,51 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
 int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 {
        u32 cid = 0;
-       struct fsa_scsi_hba *fsa_dev_ptr;
-       int cardtype;
-       int ret;
        struct Scsi_Host *host = scsicmd->device->host;
        struct aac_dev *dev = (struct aac_dev *)host->hostdata;
+       struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
        
-       cardtype = dev->cardtype;
-
-       fsa_dev_ptr = fsa_dev[host->unique_id];
-
+       if (fsa_dev_ptr == NULL)
+               return -1;
        /*
-        *      If the bus, target or lun is out of range, return fail
+        *      If the bus, id or lun is out of range, return fail
         *      Test does not apply to ID 16, the pseudo id for the controller
         *      itself.
         */
-       if (scsicmd->device->id != host->this_id) {
-               if ((scsicmd->device->channel == 0) ){
-                       if( (scsicmd->device->id >= AAC_MAX_TARGET) || (scsicmd->device->lun != 0)){ 
+       if (scmd_id(scsicmd) != host->this_id) {
+               if ((scmd_channel(scsicmd) == CONTAINER_CHANNEL)) {
+                       if((scmd_id(scsicmd) >= dev->maximum_num_containers) ||
+                                       (scsicmd->device->lun != 0)) {
                                scsicmd->result = DID_NO_CONNECT << 16;
-                               __aac_io_done(scsicmd);
+                               scsicmd->scsi_done(scsicmd);
                                return 0;
                        }
-                       cid = TARGET_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
+                       cid = scmd_id(scsicmd);
 
                        /*
                         *      If the target container doesn't exist, it may have
                         *      been newly created
                         */
-                       if (fsa_dev_ptr->valid[cid] == 0) {
+                       if ((fsa_dev_ptr[cid].valid & 1) == 0) {
                                switch (scsicmd->cmnd[0]) {
+                               case SERVICE_ACTION_IN:
+                                       if (!(dev->raw_io_interface) ||
+                                           !(dev->raw_io_64) ||
+                                           ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
+                                               break;
                                case INQUIRY:
                                case READ_CAPACITY:
                                case TEST_UNIT_READY:
+                                       if (dev->in_reset)
+                                               return -1;
                                        spin_unlock_irq(host->host_lock);
-                                       probe_container(dev, cid);
+                                       aac_probe_container(dev, cid);
+                                       if ((fsa_dev_ptr[cid].valid & 1) == 0)
+                                               fsa_dev_ptr[cid].valid = 0;
                                        spin_lock_irq(host->host_lock);
-                                       if (fsa_dev_ptr->valid[cid] == 0) {
+                                       if (fsa_dev_ptr[cid].valid == 0) {
                                                scsicmd->result = DID_NO_CONNECT << 16;
-                                               __aac_io_done(scsicmd);
+                                               scsicmd->scsi_done(scsicmd);
                                                return 0;
                                        }
                                default:
@@ -908,17 +1533,19 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                         *      If the target container still doesn't exist, 
                         *      return failure
                         */
-                       if (fsa_dev_ptr->valid[cid] == 0) {
+                       if (fsa_dev_ptr[cid].valid == 0) {
                                scsicmd->result = DID_BAD_TARGET << 16;
-                               __aac_io_done(scsicmd);
-                               return -1;
+                               scsicmd->scsi_done(scsicmd);
+                               return 0;
                        }
                } else {  /* check for physical non-dasd devices */
-                       if(dev->nondasd_support == 1){
+                       if ((dev->nondasd_support == 1) || expose_physicals) {
+                               if (dev->in_reset)
+                                       return -1;
                                return aac_send_srb_fib(scsicmd);
                        } else {
                                scsicmd->result = DID_NO_CONNECT << 16;
-                               __aac_io_done(scsicmd);
+                               scsicmd->scsi_done(scsicmd);
                                return 0;
                        }
                }
@@ -931,12 +1558,16 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
        {
                dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
-               set_sense((u8 *) &sense_data[cid],
-                           SENKEY_ILLEGAL,
+               set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+                           ILLEGAL_REQUEST,
                            SENCODE_INVALID_COMMAND,
                            ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
-               __aac_io_done(scsicmd);
-               return -1;
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                 (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+                   ? sizeof(scsicmd->sense_buffer)
+                   : sizeof(dev->fsa_dev[cid].sense_data));
+               scsicmd->scsi_done(scsicmd);
+               return 0;
        }
 
 
@@ -944,39 +1575,92 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
        switch (scsicmd->cmnd[0]) {
        case INQUIRY:
        {
-               struct inquiry_data *inq_data_ptr;
+               struct inquiry_data inq_data;
 
-               dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->device->id));
-               inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer;
-               memset(inq_data_ptr, 0, sizeof (struct inquiry_data));
+               dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scmd_id(scsicmd)));
+               memset(&inq_data, 0, sizeof (struct inquiry_data));
 
-               inq_data_ptr->inqd_ver = 2;     /* claim compliance to SCSI-2 */
-               inq_data_ptr->inqd_dtq = 0x80;  /* set RMB bit to one indicating that the medium is removable */
-               inq_data_ptr->inqd_rdf = 2;     /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
-               inq_data_ptr->inqd_len = 31;
+               inq_data.inqd_ver = 2;  /* claim compliance to SCSI-2 */
+               inq_data.inqd_rdf = 2;  /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
+               inq_data.inqd_len = 31;
                /*Format for "pad2" is  RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
-               inq_data_ptr->inqd_pad2= 0x32 ;  /*WBus16|Sync|CmdQue */
+               inq_data.inqd_pad2= 0x32 ;       /*WBus16|Sync|CmdQue */
                /*
                 *      Set the Vendor, Product, and Revision Level
                 *      see: <vendor>.c i.e. aac.c
                 */
-               setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr->type[cid]);
-               if (scsicmd->device->id == host->this_id)
-                       inq_data_ptr->inqd_pdt = INQD_PDT_PROC; /* Processor device */
-               else
-                       inq_data_ptr->inqd_pdt = INQD_PDT_DA;   /* Direct/random access device */
+               if (scmd_id(scsicmd) == 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));
+                       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+                       scsicmd->scsi_done(scsicmd);
+                       return 0;
+               }
+               if (dev->in_reset)
+                       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));
+               return aac_get_container_name(scsicmd, cid);
+       }
+       case SERVICE_ACTION_IN:
+               if (!(dev->raw_io_interface) ||
+                   !(dev->raw_io_64) ||
+                   ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
+                       break;
+       {
+               u64 capacity;
+               char cp[13];
+
+               dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n"));
+               capacity = fsa_dev_ptr[cid].size - 1;
+               cp[0] = (capacity >> 56) & 0xff;
+               cp[1] = (capacity >> 48) & 0xff;
+               cp[2] = (capacity >> 40) & 0xff;
+               cp[3] = (capacity >> 32) & 0xff;
+               cp[4] = (capacity >> 24) & 0xff;
+               cp[5] = (capacity >> 16) & 0xff;
+               cp[6] = (capacity >> 8) & 0xff;
+               cp[7] = (capacity >> 0) & 0xff;
+               cp[8] = 0;
+               cp[9] = 0;
+               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]);
+               }
+
+               /* Do not cache partition table for arrays */
+               scsicmd->device->removable = 1;
+
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               __aac_io_done(scsicmd);
+               scsicmd->scsi_done(scsicmd);
+
                return 0;
        }
+
        case READ_CAPACITY:
        {
-               int capacity;
-               char *cp;
+               u32 capacity;
+               char cp[8];
 
                dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
-               capacity = fsa_dev_ptr->size[cid] - 1;
-               cp = scsicmd->request_buffer;
+               if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
+                       capacity = fsa_dev_ptr[cid].size - 1;
+               else
+                       capacity = (u32)-1;
+
                cp[0] = (capacity >> 24) & 0xff;
                cp[1] = (capacity >> 16) & 0xff;
                cp[2] = (capacity >> 8) & 0xff;
@@ -985,35 +1669,37 @@ 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));
+               /* Do not cache partition table for arrays */
+               scsicmd->device->removable = 1;
 
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               __aac_io_done(scsicmd);
+               scsicmd->scsi_done(scsicmd);
 
                return 0;
        }
 
        case MODE_SENSE:
        {
-               char *mode_buf;
+               char mode_buf[4];
 
                dprintk((KERN_DEBUG "MODE SENSE command.\n"));
-               mode_buf = scsicmd->request_buffer;
                mode_buf[0] = 3;        /* Mode data length */
                mode_buf[1] = 0;        /* Medium type - default */
                mode_buf[2] = 0;        /* Device-specific param, bit 8: 0/1 = write enabled/protected */
                mode_buf[3] = 0;        /* Block descriptor length */
 
+               aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               __aac_io_done(scsicmd);
+               scsicmd->scsi_done(scsicmd);
 
                return 0;
        }
        case MODE_SENSE_10:
        {
-               char *mode_buf;
+               char mode_buf[8];
 
                dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n"));
-               mode_buf = scsicmd->request_buffer;
                mode_buf[0] = 0;        /* Mode data length (MSB) */
                mode_buf[1] = 6;        /* Mode data length (LSB) */
                mode_buf[2] = 0;        /* Medium type - default */
@@ -1022,29 +1708,30 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                mode_buf[5] = 0;        /* reserved */
                mode_buf[6] = 0;        /* Block descriptor length (MSB) */
                mode_buf[7] = 0;        /* Block descriptor length (LSB) */
+               aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
 
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               __aac_io_done(scsicmd);
+               scsicmd->scsi_done(scsicmd);
 
                return 0;
        }
        case REQUEST_SENSE:
                dprintk((KERN_DEBUG "REQUEST SENSE command.\n"));
-               memcpy(scsicmd->sense_buffer, &sense_data[cid], sizeof (struct sense_data));
-               memset(&sense_data[cid], 0, sizeof (struct sense_data));
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, sizeof (struct sense_data));
+               memset(&dev->fsa_dev[cid].sense_data, 0, sizeof (struct sense_data));
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               __aac_io_done(scsicmd);
-               return (0);
+               scsicmd->scsi_done(scsicmd);
+               return 0;
 
        case ALLOW_MEDIUM_REMOVAL:
                dprintk((KERN_DEBUG "LOCK command.\n"));
                if (scsicmd->cmnd[4])
-                       fsa_dev_ptr->locked[cid] = 1;
+                       fsa_dev_ptr[cid].locked = 1;
                else
-                       fsa_dev_ptr->locked[cid] = 0;
+                       fsa_dev_ptr[cid].locked = 0;
 
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               __aac_io_done(scsicmd);
+               scsicmd->scsi_done(scsicmd);
                return 0;
        /*
         *      These commands are all No-Ops
@@ -1057,138 +1744,157 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
        case SEEK_10:
        case START_STOP:
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               __aac_io_done(scsicmd);
-               return (0);
+               scsicmd->scsi_done(scsicmd);
+               return 0;
        }
 
        switch (scsicmd->cmnd[0]) 
        {
                case READ_6:
                case READ_10:
+               case READ_12:
+               case READ_16:
+                       if (dev->in_reset)
+                               return -1;
                        /*
                         *      Hack to keep track of ordinal number of the device that
                         *      corresponds to a container. Needed to convert
                         *      containers to /dev/sd device names
                         */
                         
-                       spin_unlock_irq(host->host_lock);
-                       if  (scsicmd->request->rq_disk)
-                               memcpy(fsa_dev_ptr->devname[cid],
-                                       scsicmd->request->rq_disk->disk_name,
-                                       8);
+                       if (scsicmd->request->rq_disk)
+                               strlcpy(fsa_dev_ptr[cid].devname,
+                               scsicmd->request->rq_disk->disk_name,
+                               min(sizeof(fsa_dev_ptr[cid].devname),
+                               sizeof(scsicmd->request->rq_disk->disk_name) + 1));
 
-                       ret = aac_read(scsicmd, cid);
-                       spin_lock_irq(host->host_lock);
-                       return ret;
+                       return aac_read(scsicmd, cid);
 
                case WRITE_6:
                case WRITE_10:
-                       spin_unlock_irq(host->host_lock);
-                       ret = aac_write(scsicmd, cid);
-                       spin_lock_irq(host->host_lock);
-                       return ret;
+               case WRITE_12:
+               case WRITE_16:
+                       if (dev->in_reset)
+                               return -1;
+                       return aac_write(scsicmd, cid);
+
+               case SYNCHRONIZE_CACHE:
+                       /* Issue FIB to tell Firmware to flush it's cache */
+                       return aac_synchronize(scsicmd, cid);
+                       
                default:
                        /*
                         *      Unhandled commands
                         */
-                       printk(KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]);
+                       dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]));
                        scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
-                       set_sense((u8 *) &sense_data[cid],
-                               SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND,
-                       ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
-                       __aac_io_done(scsicmd);
-                       return -1;
+                       set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+                               ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
+                               ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+                       memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                         (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+                           ? sizeof(scsicmd->sense_buffer)
+                           : sizeof(dev->fsa_dev[cid].sense_data));
+                       scsicmd->scsi_done(scsicmd);
+                       return 0;
        }
 }
 
-static int query_disk(struct aac_dev *dev, void *arg)
+static int query_disk(struct aac_dev *dev, void __user *arg)
 {
        struct aac_query_disk qd;
-       struct fsa_scsi_hba *fsa_dev_ptr;
+       struct fsa_dev_info *fsa_dev_ptr;
 
-       fsa_dev_ptr = &(dev->fsa_dev);
+       fsa_dev_ptr = dev->fsa_dev;
+       if (!fsa_dev_ptr)
+               return -EBUSY;
        if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
                return -EFAULT;
        if (qd.cnum == -1)
-               qd.cnum = TARGET_LUN_TO_CONTAINER(qd.target, qd.lun);
-       else if ((qd.bus == -1) && (qd.target == -1) && (qd.lun == -1)) 
+               qd.cnum = qd.id;
+       else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) 
        {
-               if (qd.cnum < 0 || qd.cnum >= MAXIMUM_NUM_CONTAINERS)
+               if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
                        return -EINVAL;
                qd.instance = dev->scsi_host_ptr->host_no;
                qd.bus = 0;
-               qd.target = CONTAINER_TO_TARGET(qd.cnum);
+               qd.id = CONTAINER_TO_ID(qd.cnum);
                qd.lun = CONTAINER_TO_LUN(qd.cnum);
        }
        else return -EINVAL;
 
-       qd.valid = fsa_dev_ptr->valid[qd.cnum];
-       qd.locked = fsa_dev_ptr->locked[qd.cnum];
-       qd.deleted = fsa_dev_ptr->deleted[qd.cnum];
+       qd.valid = fsa_dev_ptr[qd.cnum].valid;
+       qd.locked = fsa_dev_ptr[qd.cnum].locked;
+       qd.deleted = fsa_dev_ptr[qd.cnum].deleted;
 
-       if (fsa_dev_ptr->devname[qd.cnum][0] == '\0')
+       if (fsa_dev_ptr[qd.cnum].devname[0] == '\0')
                qd.unmapped = 1;
        else
                qd.unmapped = 0;
 
-       strlcpy(qd.name, fsa_dev_ptr->devname[qd.cnum], sizeof(qd.name));
+       strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname,
+         min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1));
 
        if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk)))
                return -EFAULT;
        return 0;
 }
 
-static int force_delete_disk(struct aac_dev *dev, void *arg)
+static int force_delete_disk(struct aac_dev *dev, void __user *arg)
 {
        struct aac_delete_disk dd;
-       struct fsa_scsi_hba *fsa_dev_ptr;
+       struct fsa_dev_info *fsa_dev_ptr;
 
-       fsa_dev_ptr = &(dev->fsa_dev);
+       fsa_dev_ptr = dev->fsa_dev;
+       if (!fsa_dev_ptr)
+               return -EBUSY;
 
        if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
                return -EFAULT;
 
-       if (dd.cnum >= MAXIMUM_NUM_CONTAINERS)
+       if (dd.cnum >= dev->maximum_num_containers)
                return -EINVAL;
        /*
         *      Mark this container as being deleted.
         */
-       fsa_dev_ptr->deleted[dd.cnum] = 1;
+       fsa_dev_ptr[dd.cnum].deleted = 1;
        /*
         *      Mark the container as no longer valid
         */
-       fsa_dev_ptr->valid[dd.cnum] = 0;
+       fsa_dev_ptr[dd.cnum].valid = 0;
        return 0;
 }
 
-static int delete_disk(struct aac_dev *dev, void *arg)
+static int delete_disk(struct aac_dev *dev, void __user *arg)
 {
        struct aac_delete_disk dd;
-       struct fsa_scsi_hba *fsa_dev_ptr;
+       struct fsa_dev_info *fsa_dev_ptr;
 
-       fsa_dev_ptr = &(dev->fsa_dev);
+       fsa_dev_ptr = dev->fsa_dev;
+       if (!fsa_dev_ptr)
+               return -EBUSY;
 
        if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
                return -EFAULT;
 
-       if (dd.cnum >= MAXIMUM_NUM_CONTAINERS)
+       if (dd.cnum >= dev->maximum_num_containers)
                return -EINVAL;
        /*
         *      If the container is locked, it can not be deleted by the API.
         */
-       if (fsa_dev_ptr->locked[dd.cnum])
+       if (fsa_dev_ptr[dd.cnum].locked)
                return -EBUSY;
        else {
                /*
                 *      Mark the container as no longer being valid.
                 */
-               fsa_dev_ptr->valid[dd.cnum] = 0;
-               fsa_dev_ptr->devname[dd.cnum][0] = '\0';
+               fsa_dev_ptr[dd.cnum].valid = 0;
+               fsa_dev_ptr[dd.cnum].devname[0] = '\0';
                return 0;
        }
 }
 
-int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg)
+int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg)
 {
        switch (cmd) {
        case FSACTL_QUERY_DISK:
@@ -1197,7 +1903,7 @@ int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg)
                return delete_disk(dev, arg);
        case FSACTL_FORCE_DELETE_DISK:
                return force_delete_disk(dev, arg);
-       case 2131:
+       case FSACTL_GET_CONTAINERS:
                return aac_get_containers(dev);
        default:
                return -ENOTTY;
@@ -1221,24 +1927,28 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
        struct scsi_cmnd *scsicmd;
 
        scsicmd = (struct scsi_cmnd *) context;
+       scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
        dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 
-       if (fibptr == NULL)
-               BUG();
+       BUG_ON(fibptr == NULL);
 
        srbreply = (struct aac_srb_reply *) fib_data(fibptr);
 
-       scsicmd->sense_buffer[0] = '\0';  // initialize sense valid flag to false
-       // calculate resid for sg 
-       scsicmd->resid = scsicmd->request_bufflen - srbreply->data_xfer_length;
+       scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
+       /*
+        *      Calculate resid for sg 
+        */
+        
+       scsicmd->resid = scsicmd->request_bufflen - 
+               le32_to_cpu(srbreply->data_xfer_length);
 
        if(scsicmd->use_sg)
                pci_unmap_sg(dev->pdev, 
-                       (struct scatterlist *)scsicmd->buffer,
+                       (struct scatterlist *)scsicmd->request_buffer,
                        scsicmd->use_sg,
                        scsicmd->sc_data_direction);
        else if(scsicmd->request_bufflen)
-               pci_unmap_single(dev->pdev, (ulong)scsicmd->SCp.ptr, scsicmd->request_bufflen,
+               pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, scsicmd->request_bufflen,
                        scsicmd->sc_data_direction);
 
        /*
@@ -1248,8 +1958,10 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
        if (le32_to_cpu(srbreply->status) != ST_OK){
                int len;
                printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
-               len = (srbreply->sense_data_size > sizeof(scsicmd->sense_buffer))?
-                               sizeof(scsicmd->sense_buffer):srbreply->sense_data_size;
+               len = (le32_to_cpu(srbreply->sense_data_size) > 
+                               sizeof(scsicmd->sense_buffer)) ?
+                               sizeof(scsicmd->sense_buffer) : 
+                               le32_to_cpu(srbreply->sense_data_size);
                scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
                memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
        }
@@ -1261,24 +1973,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
        case SRB_STATUS_ERROR_RECOVERY:
        case SRB_STATUS_PENDING:
        case SRB_STATUS_SUCCESS:
-               if(scsicmd->cmnd[0] == INQUIRY ){
-                       u8 b;
-                       u8 b1;
-                       /* We can't expose disk devices because we can't tell whether they
-                        * are the raw container drives or stand alone drives.  If they have
-                        * the removable bit set then we should expose them though.
-                        */
-                       b = (*(u8*)scsicmd->buffer)&0x1f;
-                       b1 = ((u8*)scsicmd->buffer)[1];
-                       if( b==TYPE_TAPE || b==TYPE_WORM || b==TYPE_ROM || b==TYPE_MOD|| b==TYPE_MEDIUM_CHANGER 
-                                       || (b==TYPE_DISK && (b1&0x80)) ){
-                               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
-                       } else {
-                               scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
-                       }
-               } else {
-                       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
-               }
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
                break;
        case SRB_STATUS_DATA_OVERRUN:
                switch(scsicmd->cmnd[0]){
@@ -1288,6 +1983,8 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
                case  WRITE_10:
                case  READ_12:
                case  WRITE_12:
+               case  READ_16:
+               case  WRITE_16:
                        if(le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow ) {
                                printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
                        } else {
@@ -1296,19 +1993,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
                        scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
                        break;
                case INQUIRY: {
-                       u8 b;
-                       u8 b1;
-                       /* We can't expose disk devices because we can't tell whether they
-                       * are the raw container drives or stand alone drives
-                       */
-                       b = (*(u8*)scsicmd->buffer)&0x0f;
-                       b1 = ((u8*)scsicmd->buffer)[1];
-                       if( b==TYPE_TAPE || b==TYPE_WORM || b==TYPE_ROM || b==TYPE_MOD|| b==TYPE_MEDIUM_CHANGER
-                                       || (b==TYPE_DISK && (b1&0x80)) ){
-                               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
-                       } else {
-                               scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
-                       }
+                       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
                        break;
                }
                default:
@@ -1366,7 +2051,12 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
        case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
        default:
 #ifdef AAC_DETAILED_STATUS_INFO
-               printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",le32_to_cpu(srbreply->srb_status&0x3f),aac_get_status_string(le32_to_cpu(srbreply->srb_status)), scsicmd->cmnd[0], le32_to_cpu(srbreply->scsi_status) );
+               printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
+                       le32_to_cpu(srbreply->srb_status) & 0x3F,
+                       aac_get_status_string(
+                               le32_to_cpu(srbreply->srb_status) & 0x3F), 
+                       scsicmd->cmnd[0], 
+                       le32_to_cpu(srbreply->scsi_status));
 #endif
                scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
                break;
@@ -1374,9 +2064,14 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
        if (le32_to_cpu(srbreply->scsi_status) == 0x02 ){  // Check Condition
                int len;
                scsicmd->result |= SAM_STAT_CHECK_CONDITION;
-               len = (srbreply->sense_data_size > sizeof(scsicmd->sense_buffer))?
-                               sizeof(scsicmd->sense_buffer):srbreply->sense_data_size;
-               printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", le32_to_cpu(srbreply->status), len);
+               len = (le32_to_cpu(srbreply->sense_data_size) > 
+                               sizeof(scsicmd->sense_buffer)) ?
+                               sizeof(scsicmd->sense_buffer) :
+                               le32_to_cpu(srbreply->sense_data_size);
+#ifdef AAC_DETAILED_STATUS_INFO
+               printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
+                                       le32_to_cpu(srbreply->status), len);
+#endif
                memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
                
        }
@@ -1385,9 +2080,9 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
         */
        scsicmd->result |= le32_to_cpu(srbreply->scsi_status);
 
-       fib_complete(fibptr);
-       fib_free(fibptr);
-       aac_io_done(scsicmd);
+       aac_fib_complete(fibptr);
+       aac_fib_free(fibptr);
+       scsicmd->scsi_done(scsicmd);
 }
 
 /**
@@ -1409,13 +2104,14 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
        u32 flag;
        u32 timeout;
 
-       if( scsicmd->device->id > 15 || scsicmd->device->lun > 7) {
+       dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+       if (scmd_id(scsicmd) >= dev->maximum_num_physicals ||
+                       scsicmd->device->lun > 7) {
                scsicmd->result = DID_NO_CONNECT << 16;
-               __aac_io_done(scsicmd);
+               scsicmd->scsi_done(scsicmd);
                return 0;
        }
 
-       dev = (struct aac_dev *)scsicmd->device->host->hostdata;
        switch(scsicmd->sc_data_direction){
        case DMA_TO_DEVICE:
                flag = SRB_DataOut;
@@ -1436,28 +2132,26 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
        /*
         *      Allocate and initialize a Fib then setup a BlockWrite command
         */
-       if (!(cmd_fibcontext = fib_alloc(dev))) {
-               scsicmd->result = DID_ERROR << 16;
-               __aac_io_done(scsicmd);
+       if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
                return -1;
        }
-       fib_init(cmd_fibcontext);
+       aac_fib_init(cmd_fibcontext);
 
        srbcmd = (struct aac_srb*) fib_data(cmd_fibcontext);
        srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
-       srbcmd->channel  = cpu_to_le32(aac_logical_to_phys(scsicmd->device->channel));
-       srbcmd->target   = cpu_to_le32(scsicmd->device->id);
+       srbcmd->channel  = cpu_to_le32(aac_logical_to_phys(scmd_channel(scsicmd)));
+       srbcmd->id   = cpu_to_le32(scmd_id(scsicmd));
        srbcmd->lun      = cpu_to_le32(scsicmd->device->lun);
        srbcmd->flags    = cpu_to_le32(flag);
-       timeout = (scsicmd->timeout-jiffies)/HZ;
+       timeout = scsicmd->timeout_per_command/HZ;
        if(timeout == 0){
                timeout = 1;
        }
        srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
-       srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
+       srbcmd->retry_limit = 0; /* Obsolete parameter */
        srbcmd->cdb_size = cpu_to_le32(scsicmd->cmd_len);
        
-       if( dev->pae_support ==1 ) {
+       if( dev->dac_support == 1 ) {
                aac_build_sg64(scsicmd, (struct sgmap64*) &srbcmd->sg);
                srbcmd->count = cpu_to_le32(scsicmd->request_bufflen);
 
@@ -1466,13 +2160,19 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
                /*
                 *      Build Scatter/Gather list
                 */
-               fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry64));
+               fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) +
+                       ((le32_to_cpu(srbcmd->sg.count) & 0xff) * 
+                        sizeof (struct sgentry64));
+               BUG_ON (fibsize > (dev->max_fib_size -
+                                       sizeof(struct aac_fibhdr)));
 
                /*
                 *      Now send the Fib to the adapter
                 */
-               status = fib_send(ScsiPortCommand64, cmd_fibcontext, fibsize, FsaNormal, 0, 1,
-                                 (fib_callback) aac_srb_callback, (void *) scsicmd);
+               status = aac_fib_send(ScsiPortCommand64, cmd_fibcontext,
+                               fibsize, FsaNormal, 0, 1,
+                                 (fib_callback) aac_srb_callback, 
+                                 (void *) scsicmd);
        } else {
                aac_build_sg(scsicmd, (struct sgmap*)&srbcmd->sg);
                srbcmd->count = cpu_to_le32(scsicmd->request_bufflen);
@@ -1482,30 +2182,29 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
                /*
                 *      Build Scatter/Gather list
                 */
-               fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
+               fibsize = sizeof (struct aac_srb) + 
+                       (((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * 
+                        sizeof (struct sgentry));
+               BUG_ON (fibsize > (dev->max_fib_size -
+                                       sizeof(struct aac_fibhdr)));
 
                /*
                 *      Now send the Fib to the adapter
                 */
-               status = fib_send(ScsiPortCommand, cmd_fibcontext, fibsize, FsaNormal, 0, 1,
+               status = aac_fib_send(ScsiPortCommand, cmd_fibcontext, fibsize, FsaNormal, 0, 1,
                                  (fib_callback) aac_srb_callback, (void *) scsicmd);
        }
        /*
         *      Check that the command queued to the controller
         */
-       if (status == -EINPROGRESS){
+       if (status == -EINPROGRESS) {
+               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
                return 0;
        }
 
-       printk(KERN_WARNING "aac_srb: fib_send failed with status: %d\n", status);
-       /*
-        *      For some reason, the Fib didn't queue, return QUEUE_FULL
-        */
-       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
-       __aac_io_done(scsicmd);
-
-       fib_complete(cmd_fibcontext);
-       fib_free(cmd_fibcontext);
+       printk(KERN_WARNING "aac_srb: aac_fib_send failed with status: %d\n", status);
+       aac_fib_complete(cmd_fibcontext);
+       aac_fib_free(cmd_fibcontext);
 
        return -1;
 }
@@ -1517,9 +2216,9 @@ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
 
        dev = (struct aac_dev *)scsicmd->device->host->hostdata;
        // Get rid of old data
-       psg->count = cpu_to_le32(0);
-       psg->sg[0].addr = cpu_to_le32(0);
-       psg->sg[0].count = cpu_to_le32(0);  
+       psg->count = 0;
+       psg->sg[0].addr = 0;
+       psg->sg[0].count = 0;  
        if (scsicmd->use_sg) {
                struct scatterlist *sg;
                int i;
@@ -1530,8 +2229,6 @@ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
                        scsicmd->sc_data_direction);
                psg->count = cpu_to_le32(sg_count);
 
-               byte_count = 0;
-
                for (i = 0; i < sg_count; i++) {
                        psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg));
                        psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
@@ -1540,7 +2237,9 @@ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
                }
                /* hba wants the size to be exact */
                if(byte_count > scsicmd->request_bufflen){
-                       psg->sg[i-1].count -= (byte_count - scsicmd->request_bufflen);
+                       u32 temp = le32_to_cpu(psg->sg[i-1].count) - 
+                               (byte_count - scsicmd->request_bufflen);
+                       psg->sg[i-1].count = cpu_to_le32(temp);
                        byte_count = scsicmd->request_bufflen;
                }
                /* Check for command underflow */
@@ -1550,15 +2249,15 @@ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
                }
        }
        else if(scsicmd->request_bufflen) {
-               dma_addr_t addr; 
-               addr = pci_map_single(dev->pdev,
+               u32 addr;
+               scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
                                scsicmd->request_buffer,
                                scsicmd->request_bufflen,
                                scsicmd->sc_data_direction);
+               addr = scsicmd->SCp.dma_handle;
                psg->count = cpu_to_le32(1);
                psg->sg[0].addr = cpu_to_le32(addr);
                psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
-               scsicmd->SCp.ptr = (char *)(ulong)addr;
                byte_count = scsicmd->request_bufflen;
        }
        return byte_count;
@@ -1569,14 +2268,14 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p
 {
        struct aac_dev *dev;
        unsigned long byte_count = 0;
-       u64 le_addr;
+       u64 addr;
 
        dev = (struct aac_dev *)scsicmd->device->host->hostdata;
        // Get rid of old data
-       psg->count = cpu_to_le32(0);
-       psg->sg[0].addr[0] = cpu_to_le32(0);
-       psg->sg[0].addr[1] = cpu_to_le32(0);
-       psg->sg[0].count = cpu_to_le32(0);  
+       psg->count = 0;
+       psg->sg[0].addr[0] = 0;
+       psg->sg[0].addr[1] = 0;
+       psg->sg[0].count = 0;
        if (scsicmd->use_sg) {
                struct scatterlist *sg;
                int i;
@@ -1585,21 +2284,86 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p
 
                sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
                        scsicmd->sc_data_direction);
+
+               for (i = 0; i < sg_count; i++) {
+                       int count = sg_dma_len(sg);
+                       addr = sg_dma_address(sg);
+                       psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
+                       psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
+                       psg->sg[i].count = cpu_to_le32(count);
+                       byte_count += count;
+                       sg++;
+               }
                psg->count = cpu_to_le32(sg_count);
+               /* hba wants the size to be exact */
+               if(byte_count > scsicmd->request_bufflen){
+                       u32 temp = le32_to_cpu(psg->sg[i-1].count) - 
+                               (byte_count - scsicmd->request_bufflen);
+                       psg->sg[i-1].count = cpu_to_le32(temp);
+                       byte_count = scsicmd->request_bufflen;
+               }
+               /* Check for command underflow */
+               if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
+                       printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
+                                       byte_count, scsicmd->underflow);
+               }
+       }
+       else if(scsicmd->request_bufflen) {
+               scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
+                               scsicmd->request_buffer,
+                               scsicmd->request_bufflen,
+                               scsicmd->sc_data_direction);
+               addr = scsicmd->SCp.dma_handle;
+               psg->count = cpu_to_le32(1);
+               psg->sg[0].addr[0] = cpu_to_le32(addr & 0xffffffff);
+               psg->sg[0].addr[1] = cpu_to_le32(addr >> 32);
+               psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
+               byte_count = scsicmd->request_bufflen;
+       }
+       return byte_count;
+}
 
-               byte_count = 0;
+static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg)
+{
+       struct Scsi_Host *host = scsicmd->device->host;
+       struct aac_dev *dev = (struct aac_dev *)host->hostdata;
+       unsigned long byte_count = 0;
+
+       // Get rid of old data
+       psg->count = 0;
+       psg->sg[0].next = 0;
+       psg->sg[0].prev = 0;
+       psg->sg[0].addr[0] = 0;
+       psg->sg[0].addr[1] = 0;
+       psg->sg[0].count = 0;
+       psg->sg[0].flags = 0;
+       if (scsicmd->use_sg) {
+               struct scatterlist *sg;
+               int i;
+               int sg_count;
+               sg = (struct scatterlist *) scsicmd->request_buffer;
+
+               sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
+                       scsicmd->sc_data_direction);
 
                for (i = 0; i < sg_count; i++) {
-                       le_addr = cpu_to_le64(sg_dma_address(sg));
-                       psg->sg[i].addr[1] = (u32)(le_addr>>32);
-                       psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff);
-                       psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
-                       byte_count += sg_dma_len(sg);
+                       int count = sg_dma_len(sg);
+                       u64 addr = sg_dma_address(sg);
+                       psg->sg[i].next = 0;
+                       psg->sg[i].prev = 0;
+                       psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32));
+                       psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
+                       psg->sg[i].count = cpu_to_le32(count);
+                       psg->sg[i].flags = 0;
+                       byte_count += count;
                        sg++;
                }
+               psg->count = cpu_to_le32(sg_count);
                /* hba wants the size to be exact */
                if(byte_count > scsicmd->request_bufflen){
-                       psg->sg[i-1].count -= (byte_count - scsicmd->request_bufflen);
+                       u32 temp = le32_to_cpu(psg->sg[i-1].count) - 
+                               (byte_count - scsicmd->request_bufflen);
+                       psg->sg[i-1].count = cpu_to_le32(temp);
                        byte_count = scsicmd->request_bufflen;
                }
                /* Check for command underflow */
@@ -1609,17 +2373,21 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p
                }
        }
        else if(scsicmd->request_bufflen) {
-               dma_addr_t addr; 
-               addr = pci_map_single(dev->pdev,
+               int count;
+               u64 addr;
+               scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
                                scsicmd->request_buffer,
                                scsicmd->request_bufflen,
                                scsicmd->sc_data_direction);
+               addr = scsicmd->SCp.dma_handle;
+               count = scsicmd->request_bufflen;
                psg->count = cpu_to_le32(1);
-               le_addr = cpu_to_le64(addr);
-               psg->sg[0].addr[1] = (u32)(le_addr>>32);
-               psg->sg[0].addr[0] = (u32)(le_addr & 0xffffffff);
-               psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
-               scsicmd->SCp.ptr = (char *)(ulong)addr;
+               psg->sg[0].next = 0;
+               psg->sg[0].prev = 0;
+               psg->sg[0].addr[1] = cpu_to_le32((u32)(addr>>32));
+               psg->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
+               psg->sg[0].count = cpu_to_le32(count);
+               psg->sg[0].flags = 0;
                byte_count = scsicmd->request_bufflen;
        }
        return byte_count;
@@ -1638,7 +2406,7 @@ static struct aac_srb_status_info srb_status_info[] = {
        { SRB_STATUS_SUCCESS,           "Success"},
        { SRB_STATUS_ABORTED,           "Aborted Command"},
        { SRB_STATUS_ABORT_FAILED,      "Abort Failed"},
-       { SRB_STATUS_ERROR,             "Error Event"}, 
+       { SRB_STATUS_ERROR,             "Error Event"},
        { SRB_STATUS_BUSY,              "Device Busy"},
        { SRB_STATUS_INVALID_REQUEST,   "Invalid Request"},
        { SRB_STATUS_INVALID_PATH_ID,   "Invalid Path ID"},
@@ -1657,7 +2425,7 @@ static struct aac_srb_status_info srb_status_info[] = {
        { SRB_STATUS_BAD_SRB_BLOCK_LENGTH,"Bad Srb Block Length"},
        { SRB_STATUS_REQUEST_FLUSHED,   "Request Flushed"},
        { SRB_STATUS_DELAYED_RETRY,     "Delayed Retry"},
-       { SRB_STATUS_INVALID_LUN,       "Invalid LUN"}, 
+       { SRB_STATUS_INVALID_LUN,       "Invalid LUN"},
        { SRB_STATUS_INVALID_TARGET_ID, "Invalid TARGET ID"},
        { SRB_STATUS_BAD_FUNCTION,      "Bad Function"},
        { SRB_STATUS_ERROR_RECOVERY,    "Error Recovery"},
@@ -1672,11 +2440,9 @@ char *aac_get_status_string(u32 status)
 {
        int i;
 
-       for(i=0; i < (sizeof(srb_status_info)/sizeof(struct aac_srb_status_info)); i++ ){
-               if(srb_status_info[i].status == status){
+       for (i = 0; i < ARRAY_SIZE(srb_status_info); i++)
+               if (srb_status_info[i].status == status)
                        return srb_status_info[i].str;
-               }
-       }
 
        return "Bad Status Code";
 }