X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fscsi%2Faacraid%2Faachba.c;h=aaf3d1983d64b870c7c4fb792460fd754eaafc29;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=bb03a95fad6a7b376d9165468ec5942e611cede3;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index bb03a95fa..aaf3d1983 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -131,47 +131,10 @@ 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 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 int aac_send_srb_fib(struct scsi_cmnd* scsicmd); @@ -183,15 +146,89 @@ static char *aac_get_status_string(u32 status); * Non dasd selection is handled entirely in aachba now */ -MODULE_PARM(nondasd, "i"); +static int nondasd = -1; +static int dacmode = -1; + +static int commit = -1; + +module_param(nondasd, int, 0); MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on"); -MODULE_PARM(dacmode, "i"); +module_param(dacmode, int, 0); MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on"); -MODULE_PARM(commit, "i"); +module_param(commit, int, 0); 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"); -static int nondasd = -1; -static int dacmode = -1; +/** + * 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 status = 0; + struct fib * fibptr; + + if (!(fibptr = fib_alloc(dev))) + return -ENOMEM; + + 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 = 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", + reply->response, reply->status, reply->data.action)); + if ((reply->response != ST_OK) + || (reply->status != CT_OK) + || (reply->data.action > CFACT_PAUSE)) { + printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n"); + status = -EINVAL; + } + } + fib_complete(fibptr); + /* Send a CT_COMMIT_CONFIG to enable discovery of devices */ + if (status >= 0) { + if (commit == 1) { + struct aac_commit_config * dinfo; + 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 = fib_send(ContainerCommand, + fibptr, + sizeof (struct aac_commit_config), + FsaNormal, + 1, 1, + NULL, NULL); + fib_complete(fibptr); + } else if (commit == 0) { + printk(KERN_WARNING + "aac_get_config_status: Foreign device configurations are being ignored\n"); + } + } + fib_free(fibptr); + return status; +} /** * aac_get_containers - list containers @@ -201,21 +238,57 @@ static int dacmode = -1; */ 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))) return -ENOMEM; - for (index = 0; index < MAXIMUM_NUM_CONTAINERS; index++) { + 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 = 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 = dresp->ContainerSwitchEntries; + fib_complete(fibptr); + } + + if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS) + maximum_num_containers = MAXIMUM_NUM_CONTAINERS; + + fsa_dev_ptr = (struct fsa_dev_info *) kmalloc( + sizeof(*fsa_dev_ptr) * maximum_num_containers, GFP_KERNEL); + if (!fsa_dev_ptr) { + fib_free(fibptr); + return -ENOMEM; + } + memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers); + + 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'; + fib_init(fibptr); dinfo = (struct aac_query_mount *) fib_data(fibptr); @@ -235,14 +308,20 @@ int aac_get_containers(struct aac_dev *dev) } dresp = (struct aac_mount *)fib_data(fibptr); + dprintk ((KERN_DEBUG + "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%u\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), + (unsigned)le32_to_cpu(dresp->mnt[0].capacity))); 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 = le32_to_cpu(dresp->mnt[0].capacity); 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); /* @@ -256,25 +335,111 @@ int aac_get_containers(struct aac_dev *dev) return status; } +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 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; + + dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies)); + if (fibptr == NULL) + BUG(); + + 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')) { + int count; + char * dp; + char * sp = get_name_reply->data; + sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0'; + while (*sp == ' ') + ++sp; + count = sizeof(((struct inquiry_data *)NULL)->inqd_pid); + dp = ((struct inquiry_data *)scsicmd->request_buffer)->inqd_pid; + if (*sp) do { + *dp++ = (*sp) ? *sp++ : ' '; + } while (--count > 0); + } + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; + + fib_complete(fibptr); + fib_free(fibptr); + aac_io_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 = fib_alloc(dev))) + return -ENOMEM; + + 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 = 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) + return 0; + + printk(KERN_WARNING "aac_get_container_name: fib_send failed with status: %d.\n", status); + fib_complete(cmd_fibcontext); + fib_free(cmd_fibcontext); + return -1; +} + /** * 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) { - 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; instance = dev->scsi_host_ptr->unique_id; if (!(fibptr = fib_alloc(dev))) @@ -304,11 +469,11 @@ static int probe_container(struct aac_dev *dev, int cid) 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 = le32_to_cpu(dresp->mnt[0].capacity); if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) - fsa_dev_ptr->ro[cid] = 1; + fsa_dev_ptr[cid].ro = 1; } error: @@ -367,14 +532,13 @@ 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) { struct scsi_inq *str; - char *findit; struct aac_driver_ident *mp; mp = aac_get_driver_ident(devtype); @@ -384,13 +548,14 @@ static void setinqstr(int devtype, void *data, int tindex) inqstrcpy (mp->vname, str->vid); inqstrcpy (mp->model, str->pid); /* last six chars reserved for vol type */ - 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); + char *findit = str->pid; + + 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) = ' '; + inqstrcpy (container_types[tindex], findit + 1); } inqstrcpy ("V1.0", str->prl); } @@ -435,20 +600,6 @@ 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; @@ -494,9 +645,31 @@ int aac_get_adapter_info(struct aac_dev* dev) dev->adapter_info.serial[1]); dev->nondasd_support = 0; + dev->raid_scsi_mode = 0; if(dev->adapter_info.options & AAC_OPT_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); } @@ -571,12 +744,15 @@ static void read_callback(void *context, struct fib * fibptr) 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], + 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, &sense_data[cid], sizeof(struct sense_data)); + 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)); } fib_complete(fibptr); fib_free(fibptr); @@ -617,12 +793,13 @@ static void write_callback(void *context, struct fib * fibptr) else { printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense((u8 *) &sense_data[cid], + 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, &sense_data[cid], sizeof(struct sense_data)); + memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, + sizeof(struct sense_data)); } fib_complete(fibptr); @@ -739,7 +916,7 @@ int aac_read(struct scsi_cmnd * scsicmd, int cid) aac_io_done(scsicmd); fib_complete(cmd_fibcontext); fib_free(cmd_fibcontext); - return -1; + return 0; } static int aac_write(struct scsi_cmnd * scsicmd, int cid) @@ -773,7 +950,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) if (!(cmd_fibcontext = fib_alloc(dev))) { scsicmd->result = DID_ERROR << 16; aac_io_done(scsicmd); - return -1; + return 0; } fib_init(cmd_fibcontext); @@ -849,9 +1026,117 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) fib_complete(cmd_fibcontext); fib_free(cmd_fibcontext); - return -1; + return 0; +} + +static void synchronize_callback(void *context, struct fib *fibptr) +{ + struct aac_synchronize_reply *synchronizereply; + struct scsi_cmnd *cmd; + + cmd = context; + + 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 = ID_LUN_TO_CONTAINER(sdev->id, sdev->lun); + printk(KERN_WARNING + "synchronize_callback: synchronize failed, status = %d\n", + 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))); + } + + fib_complete(fibptr); + fib_free(fibptr); + aac_io_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; + unsigned long flags; + + /* + * Wait for all 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->serial_number != 0) { + ++active; + break; + } + + spin_unlock_irqrestore(&sdev->list_lock, flags); + + /* + * Yield the processor (requeue for later) + */ + if (active) + return SCSI_MLQUEUE_DEVICE_BUSY; + + /* + * Alocate and initialize a Fib + */ + if (!(cmd_fibcontext = + fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) + return SCSI_MLQUEUE_HOST_BUSY; + + 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 = 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) + return 0; + + printk(KERN_WARNING + "aac_synchronize: fib_send failed with status: %d.\n", status); + fib_complete(cmd_fibcontext); + fib_free(cmd_fibcontext); + return SCSI_MLQUEUE_HOST_BUSY; +} /** * aac_scsi_cmd() - Process SCSI command @@ -864,11 +1149,11 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) int aac_scsi_cmd(struct scsi_cmnd * scsicmd) { u32 cid = 0; - int ret; struct Scsi_Host *host = scsicmd->device->host; struct aac_dev *dev = (struct aac_dev *)host->hostdata; - struct fsa_scsi_hba *fsa_dev_ptr = &dev->fsa_dev; + struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev; int cardtype = dev->cardtype; + int ret; /* * If the bus, id or lun is out of range, return fail @@ -877,9 +1162,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) */ if (scsicmd->device->id != host->this_id) { if ((scsicmd->device->channel == 0) ){ - if( (scsicmd->device->id >= MAXIMUM_NUM_CONTAINERS) || (scsicmd->device->lun != 0)){ + if( (scsicmd->device->id >= 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 = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun); @@ -888,7 +1173,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) * If the target container doesn't exist, it may have * been newly created */ - if (fsa_dev_ptr->valid[cid] == 0) { + if ((fsa_dev_ptr[cid].valid & 1) == 0) { switch (scsicmd->cmnd[0]) { case INQUIRY: case READ_CAPACITY: @@ -896,9 +1181,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) spin_unlock_irq(host->host_lock); probe_container(dev, cid); 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: @@ -909,9 +1194,9 @@ 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); + scsicmd->scsi_done(scsicmd); return 0; } } else { /* check for physical non-dasd devices */ @@ -919,7 +1204,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) return aac_send_srb_fib(scsicmd); } else { scsicmd->result = DID_NO_CONNECT << 16; - __aac_io_done(scsicmd); + scsicmd->scsi_done(scsicmd); return 0; } } @@ -932,12 +1217,15 @@ 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], + 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); - memcpy(scsicmd->sense_buffer, &sense_data[cid], sizeof(struct sense_data)); + 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; } @@ -962,22 +1250,27 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) * Set the Vendor, Product, and Revision Level * see: .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) + if (scsicmd->device->id == host->this_id) { + setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), (sizeof(container_types)/sizeof(char *))); inq_data_ptr->inqd_pdt = INQD_PDT_PROC; /* Processor device */ - else - inq_data_ptr->inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - __aac_io_done(scsicmd); - return 0; + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; + scsicmd->scsi_done(scsicmd); + return 0; + } + setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr[cid].type); + inq_data_ptr->inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ + return aac_get_container_name(scsicmd, cid); } case READ_CAPACITY: { - int capacity; + u32 capacity; char *cp; dprintk((KERN_DEBUG "READ CAPACITY command.\n")); - capacity = fsa_dev_ptr->size[cid] - 1; + if (fsa_dev_ptr[cid].size <= 0x100000000LL) + capacity = fsa_dev_ptr[cid].size - 1; + else + capacity = (u32)-1; cp = scsicmd->request_buffer; cp[0] = (capacity >> 24) & 0xff; cp[1] = (capacity >> 16) & 0xff; @@ -989,7 +1282,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) cp[7] = 0; scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - __aac_io_done(scsicmd); + scsicmd->scsi_done(scsicmd); return 0; } @@ -1006,7 +1299,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) mode_buf[3] = 0; /* Block descriptor length */ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - __aac_io_done(scsicmd); + scsicmd->scsi_done(scsicmd); return 0; } @@ -1026,27 +1319,27 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) mode_buf[7] = 0; /* Block descriptor length (LSB) */ 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); + 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 @@ -1059,7 +1352,7 @@ 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); + scsicmd->scsi_done(scsicmd); return 0; } @@ -1075,7 +1368,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) spin_unlock_irq(host->host_lock); if (scsicmd->request->rq_disk) - memcpy(fsa_dev_ptr->devname[cid], + memcpy(fsa_dev_ptr[cid].devname, scsicmd->request->rq_disk->disk_name, 8); @@ -1089,18 +1382,25 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) ret = aac_write(scsicmd, cid); spin_lock_irq(host->host_lock); return ret; + + 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]); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense((u8 *) &sense_data[cid], + 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, &sense_data[cid], - sizeof(struct sense_data)); - __aac_io_done(scsicmd); + 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; } } @@ -1108,16 +1408,16 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) 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 (copy_from_user(&qd, arg, sizeof (struct aac_query_disk))) return -EFAULT; if (qd.cnum == -1) qd.cnum = ID_LUN_TO_CONTAINER(qd.id, qd.lun); 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; @@ -1126,16 +1426,17 @@ static int query_disk(struct aac_dev *dev, void __user *arg) } 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; @@ -1145,49 +1446,49 @@ static int query_disk(struct aac_dev *dev, void __user *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 (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 __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 (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; } } @@ -1280,8 +1581,17 @@ static void aac_srb_callback(void *context, struct fib * fibptr) 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; + /* + * We will allow disk devices if in RAID/SCSI mode and + * the channel is 2 + */ + } else if ((dev->raid_scsi_mode) && + (scsicmd->device->channel == 2)) { + scsicmd->result = DID_OK << 16 | + COMMAND_COMPLETE << 8; } else { - scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; + scsicmd->result = DID_NO_CONNECT << 16 | + COMMAND_COMPLETE << 8; } } else { scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; @@ -1313,8 +1623,17 @@ static void aac_srb_callback(void *context, struct fib * fibptr) 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; + /* + * We will allow disk devices if in RAID/SCSI mode and + * the channel is 2 + */ + } else if ((dev->raid_scsi_mode) && + (scsicmd->device->channel == 2)) { + scsicmd->result = DID_OK << 16 | + COMMAND_COMPLETE << 8; } else { - scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; + scsicmd->result = DID_NO_CONNECT << 16 | + COMMAND_COMPLETE << 8; } break; } @@ -1426,7 +1745,7 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) if( scsicmd->device->id > 15 || scsicmd->device->lun > 7) { scsicmd->result = DID_NO_CONNECT << 16; - __aac_io_done(scsicmd); + scsicmd->scsi_done(scsicmd); return 0; }