ips.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:261k
- (!ha->func.erasebios) ||
- (!ha->func.verifybios)) {
- pt->BasicStatus = 0x0B;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_ERROR << 16;
- return (IPS_FAILURE);
- }
- /* must have a buffer */
- if ((!pt->CmdBSize) || (!pt->CmdBuffer)) {
- pt->BasicStatus = 0x0B;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_ERROR << 16;
- return (IPS_FAILURE);
- }
- /* make sure buffer is big enough */
- if (pt->CmdBSize > ha->ioctl_datasize) {
- void *bigger_struct;
- u_int32_t count;
- u_int32_t order;
- /* try to allocate a bigger struct */
- for (count = PAGE_SIZE, order = 0;
- count < pt->CmdBSize;
- order++, count <<= 1);
- bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
- if (bigger_struct) {
- /* free the old memory */
- free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
- /* use the new memory */
- ha->ioctl_data = (char *) bigger_struct;
- ha->ioctl_order = order;
- ha->ioctl_datasize = count;
- } else {
- pt->BasicStatus = 0x0B;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_ERROR << 16;
- spin_unlock(&ha->ips_lock);
- return (IPS_FAILURE);
- }
- }
- /* copy in the buffer */
- if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
- DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
- ips_name, ha->host_num);
- pt->BasicStatus = 0x0B;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_ERROR << 16;
- return (EFAULT);
- }
- flash_data.userbuffer = pt->CmdBuffer;
- flash_data.usersize = pt->CmdBSize;
- flash_data.kernbuffer = ha->ioctl_data;
- flash_data.kernsize = ha->ioctl_datasize;
- flash_data.offset = le32_to_cpu(pt->CoppCP.cmd.flashbios.offset);
- flash_data.SC = (void *) SC;
- flash_data.pt = (void *) pt;
- flash_data.ha = (void *) ha;
- sema_init( &ha->flash_ioctl_sem, 0 );
- flash_data.sem = &ha->flash_ioctl_sem;
- task.sync = 0;
- task.routine = ips_flash_bios_section;
- task.data = (void *) &flash_data;
- /* Unlock the master lock */
- spin_unlock_irq(&io_request_lock);
- queue_task(&task, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-
- /* Wait for the flash to complete */
- down(&ha->flash_ioctl_sem);
- /* Obtain the master lock */
- spin_lock_irq(&io_request_lock);
- return (flash_data.retcode);
- }
- if ((pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) &&
- (pt->CoppCP.cmd.flashfw.type == 1) &&
- (pt->CoppCP.cmd.flashfw.direction == 3) &&
- (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
- /* Erase the Card BIOS */
- if (!ha->func.erasebios) {
- pt->BasicStatus = 0x0B;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_ERROR << 16;
- return (IPS_FAILURE);
- }
- if ((*ha->func.erasebios)(ha)) {
- DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
- ips_name, ha->host_num);
- pt->BasicStatus = 0x0B;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_ERROR << 16;
- return (IPS_FAILURE);
- }
- SC->result = DID_OK << 16;
- pt->BasicStatus = 0x00;
- pt->ExtendedStatus = 0x00;
- return (IPS_SUCCESS_IMM);
- }
- if (ips_newusrcmd(ha, pt, scb))
- return (IPS_SUCCESS);
- else
- return (IPS_FAILURE);
- }
- break;
- } /* end switch */
- return (IPS_FAILURE);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_scheduled_flash_bios */
- /* */
- /* Routine Description: */
- /* */
- /* Flash the BIOS on a Copperhead style controller */
- /* To be called from a task queue */
- /* */
- /****************************************************************************/
- static void
- ips_scheduled_flash_bios(void *data) {
- ips_ha_t *ha;
- Scsi_Cmnd *SC;
- ips_passthru_t *pt;
- IPS_FLASH_DATA *fd;
- fd = (IPS_FLASH_DATA *) data;
- ha = (ips_ha_t *) fd->ha;
- pt = (ips_passthru_t *) fd->pt;
- SC = (Scsi_Cmnd *) fd->SC;
- /*
- * Set initial return codes
- */
- SC->result = DID_OK << 16;
- pt->BasicStatus = 0x00;
- pt->ExtendedStatus = 0x00;
- fd->retcode = IPS_SUCCESS_IMM;
- /*
- * Fix the size/ptr to account for the
- * flash header
- */
- fd->kernbuffer += 0xC0;
- fd->kernsize -= 0xC0;
- fd->userbuffer += 0xC0;
- fd->usersize -= 0xC0;
- if ((*ha->func.erasebios)(ha)) {
- DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
- ips_name, ha->host_num);
- pt->BasicStatus = 0x0B;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_ERROR << 16;
- fd->retcode = IPS_FAILURE;
- up(fd->sem);
- return ;
- }
- ips_flash_bios_segment(data);
- if (fd->retcode == IPS_FAILURE)
- return ;
- if ((*ha->func.verifybios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) {
- DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash",
- ips_name, ha->host_num);
- pt->BasicStatus = 0x0B;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_ERROR << 16;
- fd->retcode = IPS_FAILURE;
- up(fd->sem);
- return ;
- }
- /* Tell them we are done */
- if (fd->retcode != IPS_FAILURE)
- up(fd->sem);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_flash_bios_section */
- /* */
- /* Routine Description: */
- /* */
- /* wrapper for ips_flash_bios_segment that raises the semaphore */
- /* */
- /****************************************************************************/
- static void
- ips_flash_bios_section(void *data) {
- ips_ha_t *ha;
- Scsi_Cmnd *SC;
- ips_passthru_t *pt;
- IPS_FLASH_DATA *fd;
- fd = (IPS_FLASH_DATA *) data;
- ha = (ips_ha_t *) fd->ha;
- pt = (ips_passthru_t *) fd->pt;
- SC = (Scsi_Cmnd *) fd->SC;
- /*
- * Set initial return codes
- */
- SC->result = DID_OK << 16;
- pt->BasicStatus = 0x00;
- pt->ExtendedStatus = 0x00;
- fd->retcode = IPS_SUCCESS_IMM;
- ips_flash_bios_segment(data);
- if (fd->retcode != IPS_FAILURE)
- up(fd->sem);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_flash_bios_segment */
- /* */
- /* Routine Description: */
- /* */
- /* Flash a portion of the BIOS on a Copperhead style controller */
- /* To be called from a task queue */
- /* */
- /****************************************************************************/
- static void
- ips_flash_bios_segment(void *data) {
- ips_ha_t *ha;
- Scsi_Cmnd *SC;
- ips_passthru_t *pt;
- IPS_FLASH_DATA *fd;
- fd = (IPS_FLASH_DATA *) data;
- ha = (ips_ha_t *) fd->ha;
- pt = (ips_passthru_t *) fd->pt;
- SC = (Scsi_Cmnd *) fd->SC;
- if ((*ha->func.programbios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) {
- DEBUG_VAR(1, "(%s%d) flash bios failed - unable to program flash",
- ips_name, ha->host_num);
- pt->BasicStatus = 0x0B;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_ERROR << 16;
- fd->retcode = IPS_FAILURE;
- up(fd->sem);
- return ;
- }
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_usrcmd */
- /* */
- /* Routine Description: */
- /* */
- /* Process a user command and make it ready to send */
- /* */
- /****************************************************************************/
- static int
- ips_usrcmd(ips_ha_t *ha, ips_passthru_t *pt, ips_scb_t *scb) {
- IPS_SG_LIST *sg_list;
- METHOD_TRACE("ips_usrcmd", 1);
- if ((!scb) || (!pt) || (!ha))
- return (0);
- /* Save the S/G list pointer so it doesn't get clobbered */
- sg_list = scb->sg_list;
- /* copy in the CP */
- memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof(IPS_IOCTL_CMD));
- memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof(IPS_DCDB_TABLE));
- /* FIX stuff that might be wrong */
- scb->sg_list = sg_list;
- scb->scb_busaddr = VIRT_TO_BUS(scb);
- scb->bus = scb->scsi_cmd->channel;
- scb->target_id = scb->scsi_cmd->target;
- scb->lun = scb->scsi_cmd->lun;
- scb->sg_len = 0;
- scb->data_len = 0;
- scb->flags = 0;
- scb->op_code = 0;
- scb->callback = ipsintr_done;
- scb->timeout = ips_cmd_timeout;
- scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
- /* we don't support DCDB/READ/WRITE Scatter Gather */
- if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) ||
- (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) ||
- (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG))
- return (0);
- if (pt->CmdBSize) {
- scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + sizeof(ips_passthru_t));
- } else {
- scb->data_busaddr = 0L;
- }
- if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
- scb->cmd.dcdb.dcdb_address = cpu_to_le32(VIRT_TO_BUS(&scb->dcdb));
- if (pt->CmdBSize) {
- if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
- scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
- else
- scb->cmd.basic_io.sg_addr = cpu_to_le32(scb->data_busaddr);
- }
- /* set timeouts */
- if (pt->TimeOut) {
- scb->timeout = pt->TimeOut;
- if (pt->TimeOut <= 10)
- scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
- else if (pt->TimeOut <= 60)
- scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
- else
- scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
- }
- /* assume success */
- scb->scsi_cmd->result = DID_OK << 16;
- /* success */
- return (1);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_newusrcmd */
- /* */
- /* Routine Description: */
- /* */
- /* Process a user command and make it ready to send */
- /* */
- /****************************************************************************/
- static int
- ips_newusrcmd(ips_ha_t *ha, ips_passthru_t *pt, ips_scb_t *scb) {
- IPS_SG_LIST *sg_list;
- char *user_area;
- char *kern_area;
- u_int32_t datasize;
- METHOD_TRACE("ips_usrcmd", 1);
- if ((!scb) || (!pt) || (!ha))
- return (0);
- /* Save the S/G list pointer so it doesn't get clobbered */
- sg_list = scb->sg_list;
- /* copy in the CP */
- memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof(IPS_IOCTL_CMD));
- memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof(IPS_DCDB_TABLE));
- /* FIX stuff that might be wrong */
- scb->sg_list = sg_list;
- scb->scb_busaddr = VIRT_TO_BUS(scb);
- scb->bus = scb->scsi_cmd->channel;
- scb->target_id = scb->scsi_cmd->target;
- scb->lun = scb->scsi_cmd->lun;
- scb->sg_len = 0;
- scb->data_len = 0;
- scb->flags = 0;
- scb->op_code = 0;
- scb->callback = ipsintr_done;
- scb->timeout = ips_cmd_timeout;
- scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
- /* we don't support DCDB/READ/WRITE Scatter Gather */
- if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) ||
- (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) ||
- (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG))
- return (0);
- if (pt->CmdBSize) {
- if (pt->CmdBSize > ha->ioctl_datasize) {
- void *bigger_struct;
- u_int32_t count;
- u_int32_t order;
- /* try to allocate a bigger struct */
- for (count = PAGE_SIZE, order = 0;
- count < pt->CmdBSize;
- order++, count <<= 1);
- bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
- if (bigger_struct) {
- /* free the old memory */
- free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
- /* use the new memory */
- ha->ioctl_data = (char *) bigger_struct;
- ha->ioctl_order = order;
- ha->ioctl_datasize = count;
- } else
- return (0);
- }
- scb->data_busaddr = VIRT_TO_BUS(ha->ioctl_data);
- /* Attempt to copy in the data */
- user_area = *((char **) &scb->scsi_cmd->cmnd[4]);
- kern_area = ha->ioctl_data;
- datasize = *((u_int32_t *) &scb->scsi_cmd->cmnd[8]);
- if (copy_from_user(kern_area, user_area, datasize) > 0) {
- DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy in user data",
- ips_name, ha->host_num);
- return (0);
- }
- } else {
- scb->data_busaddr = 0L;
- }
- if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
- scb->cmd.dcdb.dcdb_address = cpu_to_le32(VIRT_TO_BUS(&scb->dcdb));
- if (pt->CmdBSize) {
- if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
- scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
- else
- scb->cmd.basic_io.sg_addr = cpu_to_le32(scb->data_busaddr);
- }
- /* set timeouts */
- if (pt->TimeOut) {
- scb->timeout = pt->TimeOut;
- if (pt->TimeOut <= 10)
- scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
- else if (pt->TimeOut <= 60)
- scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
- else
- scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
- }
- /* assume success */
- scb->scsi_cmd->result = DID_OK << 16;
- /* success */
- return (1);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_cleanup_passthru */
- /* */
- /* Routine Description: */
- /* */
- /* Cleanup after a passthru command */
- /* */
- /****************************************************************************/
- static void
- ips_cleanup_passthru(ips_ha_t *ha, ips_scb_t *scb) {
- ips_passthru_t *pt;
- METHOD_TRACE("ips_cleanup_passthru", 1);
- if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) {
- DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru",
- ips_name, ha->host_num);
- return ;
- }
- pt = (ips_passthru_t *) scb->scsi_cmd->request_buffer;
- /* Copy data back to the user */
- if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) /* Copy DCDB Back to Caller's Area */
- memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof(IPS_DCDB_TABLE));
-
- pt->BasicStatus = scb->basic_status;
- pt->ExtendedStatus = scb->extended_status;
- if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
- up(&ha->ioctl_sem);
-
- }
- #endif
- /****************************************************************************/
- /* */
- /* Routine Name: ips_host_info */
- /* */
- /* Routine Description: */
- /* */
- /* The passthru interface for the driver */
- /* */
- /****************************************************************************/
- static int
- ips_host_info(ips_ha_t *ha, char *ptr, off_t offset, int len) {
- IPS_INFOSTR info;
- METHOD_TRACE("ips_host_info", 1);
- info.buffer = ptr;
- info.length = len;
- info.offset = offset;
- info.pos = 0;
- info.localpos = 0;
- copy_info(&info, "nIBM ServeRAID General Information:nn");
- if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) &&
- (le16_to_cpu(ha->nvram->adapter_type) != 0))
- copy_info(&info, "tController Type : %sn", ips_adapter_name[ha->ad_type-1]);
- else
- copy_info(&info, "tController Type : Unknownn");
- if (ha->io_addr)
- copy_info(&info, "tIO region : 0x%lx (%d bytes)n",
- ha->io_addr, ha->io_len);
- if (ha->mem_addr) {
- copy_info(&info, "tMemory region : 0x%lx (%d bytes)n",
- ha->mem_addr, ha->mem_len);
- copy_info(&info, "tShared memory address : 0x%lxn", ha->mem_ptr);
- }
- copy_info(&info, "tIRQ number : %dn", ha->irq);
- if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG)
- copy_info(&info, "tBIOS Version : %c%c%c%c%c%c%c%cn",
- ha->nvram->bios_high[0], ha->nvram->bios_high[1],
- ha->nvram->bios_high[2], ha->nvram->bios_high[3],
- ha->nvram->bios_low[0], ha->nvram->bios_low[1],
- ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
- copy_info(&info, "tFirmware Version : %c%c%c%c%c%c%c%cn",
- ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
- ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
- ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
- ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]);
- copy_info(&info, "tBoot Block Version : %c%c%c%c%c%c%c%cn",
- ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
- ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
- ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
- ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]);
- copy_info(&info, "tDriver Version : %s%sn",
- IPS_VERSION_HIGH, IPS_VERSION_LOW);
- copy_info(&info, "tMax Physical Devices : %dn",
- ha->enq->ucMaxPhysicalDevices);
- copy_info(&info, "tMax Active Commands : %dn",
- ha->max_cmds);
- copy_info(&info, "tCurrent Queued Commands : %dn",
- ha->scb_waitlist.count);
- copy_info(&info, "tCurrent Active Commands : %dn",
- ha->scb_activelist.count - ha->num_ioctl);
- copy_info(&info, "tCurrent Queued PT Commands : %dn",
- ha->copp_waitlist.count);
- copy_info(&info, "tCurrent Active PT Commands : %dn",
- ha->num_ioctl);
- copy_info(&info, "n");
- return (info.localpos);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: copy_mem_info */
- /* */
- /* Routine Description: */
- /* */
- /* Copy data into an IPS_INFOSTR structure */
- /* */
- /****************************************************************************/
- static void
- copy_mem_info(IPS_INFOSTR *info, char *data, int len) {
- METHOD_TRACE("copy_mem_info", 1);
- if (info->pos + len < info->offset) {
- info->pos += len;
- return;
- }
- if (info->pos < info->offset) {
- data += (info->offset - info->pos);
- len -= (info->offset - info->pos);
- info->pos += (info->offset - info->pos);
- }
- if (info->localpos + len > info->length)
- len = info->length - info->localpos;
- if (len > 0) {
- memcpy(info->buffer + info->localpos, data, len);
- info->pos += len;
- info->localpos += len;
- }
- }
- /****************************************************************************/
- /* */
- /* Routine Name: copy_info */
- /* */
- /* Routine Description: */
- /* */
- /* printf style wrapper for an info structure */
- /* */
- /****************************************************************************/
- static int
- copy_info(IPS_INFOSTR *info, char *fmt, ...) {
- va_list args;
- char buf[128];
- int len;
- METHOD_TRACE("copy_info", 1);
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
- copy_mem_info(info, buf, len);
- return (len);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_identify_controller */
- /* */
- /* Routine Description: */
- /* */
- /* Identify this controller */
- /* */
- /****************************************************************************/
- static void
- ips_identify_controller(ips_ha_t *ha) {
- METHOD_TRACE("ips_identify_controller", 1);
- switch (ha->device_id) {
- case IPS_DEVICEID_COPPERHEAD:
- if (ha->revision_id <= IPS_REVID_SERVERAID) {
- ha->ad_type = IPS_ADTYPE_SERVERAID;
- } else if (ha->revision_id == IPS_REVID_SERVERAID2) {
- ha->ad_type = IPS_ADTYPE_SERVERAID2;
- } else if (ha->revision_id == IPS_REVID_NAVAJO) {
- ha->ad_type = IPS_ADTYPE_NAVAJO;
- } else if ((ha->revision_id == IPS_REVID_SERVERAID2) && (ha->slot_num == 0)) {
- ha->ad_type = IPS_ADTYPE_KIOWA;
- } else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
- (ha->revision_id <= IPS_REVID_CLARINETP3)) {
- if (ha->enq->ucMaxPhysicalDevices == 15)
- ha->ad_type = IPS_ADTYPE_SERVERAID3L;
- else
- ha->ad_type = IPS_ADTYPE_SERVERAID3;
- } else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
- (ha->revision_id <= IPS_REVID_TROMBONE64)) {
- ha->ad_type = IPS_ADTYPE_SERVERAID4H;
- }
- break;
- case IPS_DEVICEID_MORPHEUS:
- switch (ha->subdevice_id) {
- case IPS_SUBDEVICEID_4L:
- ha->ad_type = IPS_ADTYPE_SERVERAID4L;
- break;
- case IPS_SUBDEVICEID_4M:
- ha->ad_type = IPS_ADTYPE_SERVERAID4M;
- break;
- case IPS_SUBDEVICEID_4MX:
- ha->ad_type = IPS_ADTYPE_SERVERAID4MX;
- break;
- case IPS_SUBDEVICEID_4LX:
- ha->ad_type = IPS_ADTYPE_SERVERAID4LX;
- break;
- }
- break;
- }
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_create_nvrampage5 */
- /* */
- /* Routine Description: */
- /* */
- /* Create a pseudo nvram page 5 */
- /* */
- /****************************************************************************/
- static void
- ips_create_nvrampage5(ips_ha_t *ha, IPS_NVRAM_P5 *nvram) {
- METHOD_TRACE("ips_create_nvrampage5", 1);
- memset(nvram, 0, sizeof(IPS_NVRAM_P5));
- nvram->signature = IPS_NVRAM_P5_SIG;
- nvram->adapter_slot = ha->slot_num;
- nvram->adapter_type = ha->ad_type;
- nvram->operating_system = IPS_OS_LINUX;
- strncpy((char *) nvram->driver_high, IPS_VERSION_HIGH, 4);
- strncpy((char *) nvram->driver_low, IPS_VERSION_LOW, 4);
- strncpy((char *) nvram->bios_high, ha->bios_version, 4);
- strncpy((char *) nvram->bios_low, ha->bios_version + 4, 4);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_get_bios_version */
- /* */
- /* Routine Description: */
- /* */
- /* Get the BIOS revision number */
- /* */
- /****************************************************************************/
- static void
- ips_get_bios_version(ips_ha_t *ha, int intr) {
- ips_scb_t *scb;
- int ret;
- u_int8_t major;
- u_int8_t minor;
- u_int8_t subminor;
- u_int8_t *buffer;
- char hexDigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
- METHOD_TRACE("ips_get_bios_version", 1);
- major = 0;
- minor = 0;
- strncpy(ha->bios_version, " ?", 8);
- if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
- if (IPS_USE_MEMIO(ha)) {
- /* Memory Mapped I/O */
- /* test 1st byte */
- writel(0, ha->mem_ptr + IPS_REG_FLAP);
- if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
- if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
- return;
- writel(cpu_to_le32(1), ha->mem_ptr + IPS_REG_FLAP);
- if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
- if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
- return;
- /* Get Major version */
- writel(cpu_to_le32(0x1FF), ha->mem_ptr + IPS_REG_FLAP);
- if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
- major = readb(ha->mem_ptr + IPS_REG_FLDP);
- /* Get Minor version */
- writel(cpu_to_le32(0x1FE), ha->mem_ptr + IPS_REG_FLAP);
- if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
- minor = readb(ha->mem_ptr + IPS_REG_FLDP);
- /* Get SubMinor version */
- writel(cpu_to_le32(0x1FD), ha->mem_ptr + IPS_REG_FLAP);
- if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
- subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
- } else {
- /* Programmed I/O */
- /* test 1st byte */
- outl(0, ha->io_addr + IPS_REG_FLAP);
- if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
- if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
- return ;
- outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
- if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
- if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
- return ;
- /* Get Major version */
- outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP);
- if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
- major = inb(ha->io_addr + IPS_REG_FLDP);
- /* Get Minor version */
- outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP);
- if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
- minor = inb(ha->io_addr + IPS_REG_FLDP);
- /* Get SubMinor version */
- outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP);
- if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
- subminor = inb(ha->io_addr + IPS_REG_FLDP);
- }
- } else {
- /* Morpheus Family - Send Command to the card */
- buffer = kmalloc(0x1000, GFP_ATOMIC);
- if (!buffer)
- return;
- memset(buffer, 0, 0x1000);
- scb = &ha->scbs[ha->max_cmds-1];
- ips_init_scb(ha, scb);
- scb->timeout = ips_cmd_timeout;
- scb->cdb[0] = IPS_CMD_RW_BIOSFW;
- scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW;
- scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
- scb->cmd.flashfw.type = 1;
- scb->cmd.flashfw.direction = 0;
- scb->cmd.flashfw.count = cpu_to_le32(0x800);
- scb->cmd.flashfw.buffer_addr = cpu_to_le32(VIRT_TO_BUS(buffer));
- scb->cmd.flashfw.total_packets = 1;
- scb->cmd.flashfw.packet_num = 0;
- /* issue the command */
- if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
- (ret == IPS_SUCCESS_IMM) ||
- ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
- /* Error occurred */
- kfree(buffer);
- return;
- }
- if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) {
- major = buffer[0x1ff + 0xC0]; /* Offset 0x1ff after the header (0xc0) */
- minor = buffer[0x1fe + 0xC0]; /* Offset 0x1fe after the header (0xc0) */
- subminor = buffer[0x1fd + 0xC0]; /* Offset 0x1fd after the header (0xc0) */
- } else {
- return;
- }
- kfree(buffer);
- }
- ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4];
- ha->bios_version[1] = '.';
- ha->bios_version[2] = hexDigits[major & 0x0F];
- ha->bios_version[3] = hexDigits[subminor];
- ha->bios_version[4] = '.';
- ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4];
- ha->bios_version[6] = hexDigits[minor & 0x0F];
- ha->bios_version[7] = 0;
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_hainit */
- /* */
- /* Routine Description: */
- /* */
- /* Initialize the controller */
- /* */
- /* NOTE: Assumes to be called from with a lock */
- /* */
- /****************************************************************************/
- static int
- ips_hainit(ips_ha_t *ha) {
- int i;
- struct timeval tv;
- METHOD_TRACE("ips_hainit", 1);
- if (!ha)
- return (0);
- if (ha->func.statinit)
- (*ha->func.statinit)(ha);
- if (ha->func.enableint)
- (*ha->func.enableint)(ha);
- /* Send FFDC */
- ha->reset_count = 1;
- do_gettimeofday(&tv);
- ha->last_ffdc = tv.tv_sec;
- ips_ffdc_reset(ha, IPS_INTR_IORL);
- if (!ips_read_config(ha, IPS_INTR_IORL)) {
- printk(KERN_WARNING "(%s%d) unable to read config from controller.n",
- ips_name, ha->host_num);
- return (0);
- } /* end if */
- if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) {
- printk(KERN_WARNING "(%s%d) unable to read controller status.n",
- ips_name, ha->host_num);
- return (0);
- }
- /* Identify this controller */
- ips_identify_controller(ha);
- if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) {
- printk(KERN_WARNING "(%s%d) unable to read subsystem parameters.n",
- ips_name, ha->host_num);
- return (0);
- }
- /* write nvram user page 5 */
- if (!ips_write_driver_status(ha, IPS_INTR_IORL)) {
- printk(KERN_WARNING "(%s%d) unable to write driver info to controller.n",
- ips_name, ha->host_num);
- return (0);
- }
- /* set limits on SID, LUN, BUS */
- ha->ntargets = IPS_MAX_TARGETS + 1;
- ha->nlun = 1;
- ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1;
- switch (ha->conf->logical_drive[0].ucStripeSize) {
- case 4:
- ha->max_xfer = 0x10000;
- break;
- case 5:
- ha->max_xfer = 0x20000;
- break;
- case 6:
- ha->max_xfer = 0x40000;
- break;
- case 7:
- default:
- ha->max_xfer = 0x80000;
- break;
- }
- /* setup max concurrent commands */
- if (le32_to_cpu(ha->subsys->param[4]) & 0x1) {
- /* Use the new method */
- ha->max_cmds = ha->enq->ucConcurrentCmdCount;
- } else {
- /* use the old method */
- switch (ha->conf->logical_drive[0].ucStripeSize) {
- case 4:
- ha->max_cmds = 32;
- break;
- case 5:
- ha->max_cmds = 16;
- break;
- case 6:
- ha->max_cmds = 8;
- break;
- case 7:
- default:
- ha->max_cmds = 4;
- break;
- }
- }
- /* set controller IDs */
- ha->ha_id[0] = IPS_ADAPTER_ID;
- for (i = 1; i < ha->nbus; i++) {
- ha->ha_id[i] = ha->conf->init_id[i-1] & 0x1f;
- ha->dcdb_active[i-1] = 0;
- }
- return (1);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_next */
- /* */
- /* Routine Description: */
- /* */
- /* Take the next command off the queue and send it to the controller */
- /* */
- /****************************************************************************/
- static void
- ips_next(ips_ha_t *ha, int intr) {
- ips_scb_t *scb;
- Scsi_Cmnd *SC;
- Scsi_Cmnd *p;
- Scsi_Cmnd *q;
- ips_copp_wait_item_t *item;
- int ret;
- int intr_status;
- unsigned long cpu_flags;
- unsigned long cpu_flags2;
- METHOD_TRACE("ips_next", 1);
- if (!ha)
- return ;
- /*
- * Block access to the queue function so
- * this command won't time out
- */
- if (intr == IPS_INTR_ON) {
- spin_lock_irqsave(&io_request_lock, cpu_flags2);
- intr_status = IPS_INTR_IORL;
- } else {
- intr_status = intr;
- /* Quiet the compiler */
- cpu_flags2 = 0;
- }
- if ((ha->subsys->param[3] & 0x300000) && ( ha->scb_activelist.count == 0 )) {
- struct timeval tv;
- do_gettimeofday(&tv);
- IPS_HA_LOCK(cpu_flags);
- if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) {
- ha->last_ffdc = tv.tv_sec;
- IPS_HA_UNLOCK(cpu_flags);
- ips_ffdc_time(ha, intr_status);
- } else {
- IPS_HA_UNLOCK(cpu_flags);
- }
- }
- if (intr == IPS_INTR_ON)
- spin_unlock_irqrestore(&io_request_lock, cpu_flags2);
- #ifndef NO_IPS_CMDLINE
- /*
- * Send passthru commands
- * These have priority over normal I/O
- * but shouldn't affect performance too much
- * since we limit the number that can be active
- * on the card at any one time
- */
- IPS_HA_LOCK(cpu_flags);
- IPS_QUEUE_LOCK(&ha->copp_waitlist);
- while ((ha->num_ioctl < IPS_MAX_IOCTL) &&
- (ha->copp_waitlist.head) &&
- (scb = ips_getscb(ha))) {
- IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
- item = ips_removeq_copp_head(&ha->copp_waitlist);
- ha->num_ioctl++;
- IPS_HA_UNLOCK(cpu_flags);
- scb->scsi_cmd = item->scsi_cmd;
- scb->sem = item->sem;
- kfree(item);
- ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
- switch (ret) {
- case IPS_FAILURE:
- if (scb->scsi_cmd) {
- scb->scsi_cmd->result = DID_ERROR << 16;
- /* raise the semaphore */
- if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
- u_int32_t datasize;
- datasize = 0;
- memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
- up(&ha->ioctl_sem);
- } else {
- scb->scsi_cmd->scsi_done(scb->scsi_cmd);
- }
- }
- ips_freescb(ha, scb);
- break;
- case IPS_SUCCESS_IMM:
- if (scb->scsi_cmd) {
- scb->scsi_cmd->result = DID_OK << 16;
- /* raise the semaphore */
- if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
- u_int32_t datasize;
- datasize = 0;
- memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
- up(&ha->ioctl_sem);
- } else {
- scb->scsi_cmd->scsi_done(scb->scsi_cmd);
- }
- }
- ips_freescb(ha, scb);
- break;
- default:
- break;
- } /* end case */
- if (ret != IPS_SUCCESS) {
- IPS_HA_LOCK(cpu_flags);
- IPS_QUEUE_LOCK(&ha->copp_waitlist);
- ha->num_ioctl--;
- continue;
- }
- ret = ips_send_cmd(ha, scb);
- if (ret == IPS_SUCCESS)
- ips_putq_scb_head(&ha->scb_activelist, scb);
- else
- ha->num_ioctl--;
- switch(ret) {
- case IPS_FAILURE:
- if (scb->scsi_cmd) {
- /* raise the semaphore */
- if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
- up(&ha->ioctl_sem);
- scb->scsi_cmd->result = DID_ERROR << 16;
- }
- ips_freescb(ha, scb);
- break;
- case IPS_SUCCESS_IMM:
- if (scb->scsi_cmd) {
- /* raise the semaphore */
- if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
- up(&ha->ioctl_sem);
- }
- ips_freescb(ha, scb);
- break;
- default:
- break;
- } /* end case */
- IPS_HA_LOCK(cpu_flags);
- IPS_QUEUE_LOCK(&ha->copp_waitlist);
- }
- IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
- IPS_HA_UNLOCK(cpu_flags);
- #endif
- /*
- * Send "Normal" I/O commands
- */
- IPS_HA_LOCK(cpu_flags);
- IPS_QUEUE_LOCK(&ha->scb_waitlist);
- p = ha->scb_waitlist.head;
- IPS_QUEUE_UNLOCK(&ha->scb_waitlist);
- while ((p) && (scb = ips_getscb(ha))) {
- if ((p->channel > 0) && (ha->dcdb_active[p->channel-1] & (1 << p->target))) {
- ips_freescb(ha, scb);
- p = (Scsi_Cmnd *) p->host_scribble;
- continue;
- }
- q = p;
- SC = ips_removeq_wait(&ha->scb_waitlist, q);
- if (SC == NULL) /* Should never happen, but good to check anyway */
- continue;
- IPS_HA_UNLOCK(cpu_flags); /* Unlock HA after command is taken off queue */
- SC->result = DID_OK;
- SC->host_scribble = NULL;
- memset(SC->sense_buffer, 0, sizeof(SC->sense_buffer));
- scb->target_id = SC->target;
- scb->lun = SC->lun;
- scb->bus = SC->channel;
- scb->scsi_cmd = SC;
- scb->breakup = 0;
- scb->data_len = 0;
- scb->callback = ipsintr_done;
- scb->timeout = ips_cmd_timeout;
- memset(&scb->cmd, 0, 16);
- /* copy in the CDB */
- memcpy(scb->cdb, SC->cmnd, SC->cmd_len);
- /* Now handle the data buffer */
- if (SC->use_sg) {
- struct scatterlist *sg;
- int i;
- sg = SC->request_buffer;
- if (SC->use_sg == 1) {
- if (sg[0].length > ha->max_xfer) {
- scb->breakup = 1;
- scb->data_len = ha->max_xfer;
- } else
- scb->data_len = sg[0].length;
- scb->dcdb.transfer_length = scb->data_len;
- scb->data_busaddr = VIRT_TO_BUS(sg[0].address);
- scb->sg_len = 0;
- } else {
- /* Check for the first Element being bigger than MAX_XFER */
- if (sg[0].length > ha->max_xfer) {
- scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(sg[0].address));
- scb->sg_list[0].length = ha->max_xfer;
- scb->data_len = ha->max_xfer;
- scb->breakup = 0;
- scb->sg_break=1;
- scb->sg_len = 1;
- }
- else {
- for (i = 0; i < SC->use_sg; i++) {
- scb->sg_list[i].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
- scb->sg_list[i].length = cpu_to_le32(sg[i].length);
-
- if (scb->data_len + sg[i].length > ha->max_xfer) {
- /*
- * Data Breakup required
- */
- scb->breakup = i;
- break;
- }
-
- scb->data_len += sg[i].length;
- }
- if (!scb->breakup)
- scb->sg_len = SC->use_sg;
- else
- scb->sg_len = scb->breakup;
- }
- scb->dcdb.transfer_length = scb->data_len;
- scb->data_busaddr = VIRT_TO_BUS(scb->sg_list);
- }
- } else {
- if (SC->request_bufflen) {
- if (SC->request_bufflen > ha->max_xfer) {
- /*
- * Data breakup required
- */
- scb->breakup = 1;
- scb->data_len = ha->max_xfer;
- } else {
- scb->data_len = SC->request_bufflen;
- }
- scb->dcdb.transfer_length = scb->data_len;
- scb->data_busaddr = VIRT_TO_BUS(SC->request_buffer);
- scb->sg_len = 0;
- } else {
- scb->data_busaddr = 0L;
- scb->sg_len = 0;
- scb->data_len = 0;
- scb->dcdb.transfer_length = 0;
- }
- }
- scb->dcdb.cmd_attribute |=
- ips_command_direction[scb->scsi_cmd->cmnd[0]];
- if (!scb->dcdb.cmd_attribute & 0x3)
- scb->dcdb.transfer_length = 0;
- if (scb->data_len >= IPS_MAX_XFER) {
- scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
- scb->dcdb.transfer_length = 0;
- }
- ret = ips_send_cmd(ha, scb);
- if (ret == IPS_SUCCESS)
- ips_putq_scb_head(&ha->scb_activelist, scb);
- switch(ret) {
- case IPS_FAILURE:
- if (scb->scsi_cmd) {
- scb->scsi_cmd->result = DID_ERROR << 16;
- scb->scsi_cmd->scsi_done(scb->scsi_cmd);
- }
- if (scb->bus)
- ha->dcdb_active[scb->bus-1] &= ~(1 << scb->target_id);
- ips_freescb(ha, scb);
- break;
- case IPS_SUCCESS_IMM:
- if (scb->scsi_cmd)
- scb->scsi_cmd->scsi_done(scb->scsi_cmd);
- if (scb->bus)
- ha->dcdb_active[scb->bus-1] &= ~(1 << scb->target_id);
- ips_freescb(ha, scb);
- break;
- default:
- break;
- } /* end case */
- p = (Scsi_Cmnd *) p->host_scribble;
- IPS_HA_LOCK(cpu_flags);
- } /* end while */
- IPS_HA_UNLOCK(cpu_flags);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_putq_scb_head */
- /* */
- /* Routine Description: */
- /* */
- /* Add an item to the head of the queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline void
- ips_putq_scb_head(ips_scb_queue_t *queue, ips_scb_t *item) {
- METHOD_TRACE("ips_putq_scb_head", 1);
- if (!item)
- return ;
- IPS_QUEUE_LOCK(queue);
- item->q_next = queue->head;
- queue->head = item;
- if (!queue->tail)
- queue->tail = item;
- queue->count++;
- IPS_QUEUE_UNLOCK(queue);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_putq_scb_tail */
- /* */
- /* Routine Description: */
- /* */
- /* Add an item to the tail of the queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline void
- ips_putq_scb_tail(ips_scb_queue_t *queue, ips_scb_t *item) {
- METHOD_TRACE("ips_putq_scb_tail", 1);
- if (!item)
- return ;
- IPS_QUEUE_LOCK(queue);
- item->q_next = NULL;
- if (queue->tail)
- queue->tail->q_next = item;
- queue->tail = item;
- if (!queue->head)
- queue->head = item;
- queue->count++;
- IPS_QUEUE_UNLOCK(queue);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_removeq_scb_head */
- /* */
- /* Routine Description: */
- /* */
- /* Remove the head of the queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline ips_scb_t *
- ips_removeq_scb_head(ips_scb_queue_t *queue) {
- ips_scb_t *item;
- METHOD_TRACE("ips_removeq_scb_head", 1);
- IPS_QUEUE_LOCK(queue);
- item = queue->head;
- if (!item) {
- IPS_QUEUE_UNLOCK(queue);
- return (NULL);
- }
- queue->head = item->q_next;
- item->q_next = NULL;
- if (queue->tail == item)
- queue->tail = NULL;
- queue->count--;
- IPS_QUEUE_UNLOCK(queue);
- return (item);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_removeq_scb */
- /* */
- /* Routine Description: */
- /* */
- /* Remove an item from a queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline ips_scb_t *
- ips_removeq_scb(ips_scb_queue_t *queue, ips_scb_t *item) {
- ips_scb_t *p;
- METHOD_TRACE("ips_removeq_scb", 1);
- if (!item)
- return (NULL);
- IPS_QUEUE_LOCK(queue);
- if (item == queue->head) {
- IPS_QUEUE_UNLOCK(queue);
- return (ips_removeq_scb_head(queue));
- }
- p = queue->head;
- while ((p) && (item != p->q_next))
- p = p->q_next;
- if (p) {
- /* found a match */
- p->q_next = item->q_next;
- if (!item->q_next)
- queue->tail = p;
- item->q_next = NULL;
- queue->count--;
- IPS_QUEUE_UNLOCK(queue);
- return (item);
- }
- IPS_QUEUE_UNLOCK(queue);
- return (NULL);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_putq_wait_head */
- /* */
- /* Routine Description: */
- /* */
- /* Add an item to the head of the queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline void
- ips_putq_wait_head(ips_wait_queue_t *queue, Scsi_Cmnd *item) {
- METHOD_TRACE("ips_putq_wait_head", 1);
- if (!item)
- return ;
- IPS_QUEUE_LOCK(queue);
- item->host_scribble = (char *) queue->head;
- queue->head = item;
- if (!queue->tail)
- queue->tail = item;
- queue->count++;
- IPS_QUEUE_UNLOCK(queue);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_putq_wait_tail */
- /* */
- /* Routine Description: */
- /* */
- /* Add an item to the tail of the queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline void
- ips_putq_wait_tail(ips_wait_queue_t *queue, Scsi_Cmnd *item) {
- METHOD_TRACE("ips_putq_wait_tail", 1);
- if (!item)
- return ;
- IPS_QUEUE_LOCK(queue);
- item->host_scribble = NULL;
- if (queue->tail)
- queue->tail->host_scribble = (char *)item;
- queue->tail = item;
- if (!queue->head)
- queue->head = item;
- queue->count++;
- IPS_QUEUE_UNLOCK(queue);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_removeq_wait_head */
- /* */
- /* Routine Description: */
- /* */
- /* Remove the head of the queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline Scsi_Cmnd *
- ips_removeq_wait_head(ips_wait_queue_t *queue) {
- Scsi_Cmnd *item;
- METHOD_TRACE("ips_removeq_wait_head", 1);
- IPS_QUEUE_LOCK(queue);
- item = queue->head;
- if (!item) {
- IPS_QUEUE_UNLOCK(queue);
- return (NULL);
- }
- queue->head = (Scsi_Cmnd *) item->host_scribble;
- item->host_scribble = NULL;
- if (queue->tail == item)
- queue->tail = NULL;
- queue->count--;
- IPS_QUEUE_UNLOCK(queue);
- return (item);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_removeq_wait */
- /* */
- /* Routine Description: */
- /* */
- /* Remove an item from a queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline Scsi_Cmnd *
- ips_removeq_wait(ips_wait_queue_t *queue, Scsi_Cmnd *item) {
- Scsi_Cmnd *p;
- METHOD_TRACE("ips_removeq_wait", 1);
- if (!item)
- return (NULL);
- IPS_QUEUE_LOCK(queue);
- if (item == queue->head) {
- IPS_QUEUE_UNLOCK(queue);
- return (ips_removeq_wait_head(queue));
- }
- p = queue->head;
- while ((p) && (item != (Scsi_Cmnd *) p->host_scribble))
- p = (Scsi_Cmnd *) p->host_scribble;
- if (p) {
- /* found a match */
- p->host_scribble = item->host_scribble;
- if (!item->host_scribble)
- queue->tail = p;
- item->host_scribble = NULL;
- queue->count--;
- IPS_QUEUE_UNLOCK(queue);
- return (item);
- }
- IPS_QUEUE_UNLOCK(queue);
- return (NULL);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_putq_copp_head */
- /* */
- /* Routine Description: */
- /* */
- /* Add an item to the head of the queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline void
- ips_putq_copp_head(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) {
- METHOD_TRACE("ips_putq_copp_head", 1);
- if (!item)
- return ;
- IPS_QUEUE_LOCK(queue);
- item->next = queue->head;
- queue->head = item;
- if (!queue->tail)
- queue->tail = item;
- queue->count++;
- IPS_QUEUE_UNLOCK(queue);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_putq_copp_tail */
- /* */
- /* Routine Description: */
- /* */
- /* Add an item to the tail of the queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline void
- ips_putq_copp_tail(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) {
- METHOD_TRACE("ips_putq_copp_tail", 1);
- if (!item)
- return ;
- IPS_QUEUE_LOCK(queue);
- item->next = NULL;
- if (queue->tail)
- queue->tail->next = item;
- queue->tail = item;
- if (!queue->head)
- queue->head = item;
- queue->count++;
- IPS_QUEUE_UNLOCK(queue);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_removeq_copp_head */
- /* */
- /* Routine Description: */
- /* */
- /* Remove the head of the queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline ips_copp_wait_item_t *
- ips_removeq_copp_head(ips_copp_queue_t *queue) {
- ips_copp_wait_item_t *item;
- METHOD_TRACE("ips_removeq_copp_head", 1);
- IPS_QUEUE_LOCK(queue);
- item = queue->head;
- if (!item) {
- IPS_QUEUE_UNLOCK(queue);
- return (NULL);
- }
- queue->head = item->next;
- item->next = NULL;
- if (queue->tail == item)
- queue->tail = NULL;
- queue->count--;
- IPS_QUEUE_UNLOCK(queue);
- return (item);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_removeq_copp */
- /* */
- /* Routine Description: */
- /* */
- /* Remove an item from a queue */
- /* */
- /* ASSUMED to be called from within a lock */
- /* */
- /****************************************************************************/
- static inline ips_copp_wait_item_t *
- ips_removeq_copp(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) {
- ips_copp_wait_item_t *p;
- METHOD_TRACE("ips_removeq_copp", 1);
- if (!item)
- return (NULL);
- IPS_QUEUE_LOCK(queue);
- if (item == queue->head) {
- IPS_QUEUE_UNLOCK(queue);
- return (ips_removeq_copp_head(queue));
- }
- p = queue->head;
- while ((p) && (item != p->next))
- p = p->next;
- if (p) {
- /* found a match */
- p->next = item->next;
- if (!item->next)
- queue->tail = p;
- item->next = NULL;
- queue->count--;
- IPS_QUEUE_UNLOCK(queue);
- return (item);
- }
- IPS_QUEUE_UNLOCK(queue);
- return (NULL);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ipsintr_blocking */
- /* */
- /* Routine Description: */
- /* */
- /* Finalize an interrupt for internal commands */
- /* */
- /****************************************************************************/
- static void
- ipsintr_blocking(ips_ha_t *ha, ips_scb_t *scb) {
- METHOD_TRACE("ipsintr_blocking", 2);
- if ((ha->waitflag == TRUE) &&
- (ha->cmd_in_progress == scb->cdb[0])) {
- ha->waitflag = FALSE;
- return ;
- }
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ipsintr_done */
- /* */
- /* Routine Description: */
- /* */
- /* Finalize an interrupt for non-internal commands */
- /* */
- /****************************************************************************/
- static void
- ipsintr_done(ips_ha_t *ha, ips_scb_t *scb) {
- METHOD_TRACE("ipsintr_done", 2);
- if (!scb) {
- printk(KERN_WARNING "(%s%d) Spurious interrupt; scb NULL.n",
- ips_name, ha->host_num);
- return ;
- }
- if (scb->scsi_cmd == NULL) {
- /* unexpected interrupt */
- printk(KERN_WARNING "(%s%d) Spurious interrupt; scsi_cmd not set.n",
- ips_name, ha->host_num);
- return;
- }
- ips_done(ha, scb);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_done */
- /* */
- /* Routine Description: */
- /* */
- /* Do housekeeping on completed commands */
- /* */
- /****************************************************************************/
- static void
- ips_done(ips_ha_t *ha, ips_scb_t *scb) {
- int ret;
- unsigned long cpu_flags;
- METHOD_TRACE("ips_done", 1);
- if (!scb)
- return ;
- #ifndef NO_IPS_CMDLINE
- if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) {
- ips_cleanup_passthru(ha, scb);
- IPS_HA_LOCK(cpu_flags);
- ha->num_ioctl--;
- IPS_HA_UNLOCK(cpu_flags);
- } else {
- #endif
- /*
- * Check to see if this command had too much
- * data and had to be broke up. If so, queue
- * the rest of the data and continue.
- */
- if (scb->breakup) {
- /* we had a data breakup */
- u_int8_t bk_save;
- bk_save = scb->breakup;
- scb->breakup = 0;
- if (scb->scsi_cmd->use_sg) {
- /* S/G request */
- struct scatterlist *sg;
- int i;
- sg = scb->scsi_cmd->request_buffer;
- if (scb->scsi_cmd->use_sg == 1) {
- if (sg[0].length - (bk_save * ha->max_xfer) > ha->max_xfer) {
- /* Further breakup required */
- scb->data_len = ha->max_xfer;
- scb->data_busaddr = VIRT_TO_BUS(sg[0].address + (bk_save * ha->max_xfer));
- scb->breakup = bk_save + 1;
- } else {
- scb->data_len = sg[0].length - (bk_save * ha->max_xfer);
- scb->data_busaddr = VIRT_TO_BUS(sg[0].address + (bk_save * ha->max_xfer));
- }
- scb->dcdb.transfer_length = scb->data_len;
- scb->sg_len = 0;
- } else {
- /* We're here because there was MORE than one s/g unit. */
- /* bk_save points to which sg unit to look at */
- /* sg_break points to how far through this unit we are */
- /* NOTE: We will not move from one sg to another here, */
- /* just finish the one we are in. Not the most */
- /* efficient, but it keeps it from getting too hacky */
- /* IF sg_break is non-zero, then just work on this current sg piece, */
- /* pointed to by bk_save */
- if (scb->sg_break) {
- scb->sg_len = 1;
- scb->sg_list[0].address = VIRT_TO_BUS(sg[bk_save].address+ha->max_xfer*scb->sg_break);
- if (ha->max_xfer > sg[bk_save].length-ha->max_xfer * scb->sg_break)
- scb->sg_list[0].length = sg[bk_save].length-ha->max_xfer * scb->sg_break;
- else
- scb->sg_list[0].length = ha->max_xfer;
- scb->sg_break++; /* MUST GO HERE for math below to work */
- scb->data_len = scb->sg_list[0].length;;
- if (sg[bk_save].length <= ha->max_xfer * scb->sg_break ) {
- scb->sg_break = 0; /* No more work in this unit */
- if (( bk_save + 1 ) >= scb->scsi_cmd->use_sg)
- scb->breakup = 0;
- else
- scb->breakup = bk_save + 1;
- }
- } else {
- /* ( sg_break == 0 ), so this is our first look at a new sg piece */
- if (sg[bk_save].length > ha->max_xfer) {
- scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(sg[bk_save].address));
- scb->sg_list[0].length = ha->max_xfer;
- scb->breakup = bk_save;
- scb->sg_break = 1;
- scb->data_len = ha->max_xfer;
- scb->sg_len = 1;
- } else {
- /* OK, the next sg is a short one, so loop until full */
- scb->data_len = 0;
- scb->sg_len = 0;
- scb->sg_break = 0;
- /* We're only doing full units here */
- for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) {
- scb->sg_list[i - bk_save].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
- scb->sg_list[i - bk_save].length = cpu_to_le32(sg[i].length);
- if (scb->data_len + sg[i].length > ha->max_xfer) {
- scb->breakup = i; /* sneaky, if not more work, than breakup is 0 */
- break;
- }
- scb->data_len += sg[i].length;
- scb->sg_len++; /* only if we didn't get too big */
- }
- }
- }
- /* Also, we need to be sure we don't queue work ( breakup != 0 )
- if no more sg units for next time */
- scb->dcdb.transfer_length = scb->data_len;
- scb->data_busaddr = VIRT_TO_BUS(scb->sg_list);
- }
-
- } else {
- /* Non S/G Request */
- if ((scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) > ha->max_xfer) {
- /* Further breakup required */
- scb->data_len = ha->max_xfer;
- scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer));
- scb->breakup = bk_save + 1;
- } else {
- scb->data_len = scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer);
- scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer));
- }
- scb->dcdb.transfer_length = scb->data_len;
- scb->sg_len = 0;
- }
- scb->dcdb.cmd_attribute |=
- ips_command_direction[scb->scsi_cmd->cmnd[0]];
- if (!scb->dcdb.cmd_attribute & 0x3)
- scb->dcdb.transfer_length = 0;
- if (scb->data_len >= IPS_MAX_XFER) {
- scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
- scb->dcdb.transfer_length = 0;
- }
- ret = ips_send_cmd(ha, scb);
- switch(ret) {
- case IPS_FAILURE:
- if (scb->scsi_cmd) {
- scb->scsi_cmd->result = DID_ERROR << 16;
- scb->scsi_cmd->scsi_done(scb->scsi_cmd);
- }
- ips_freescb(ha, scb);
- break;
- case IPS_SUCCESS_IMM:
- if (scb->scsi_cmd) {
- scb->scsi_cmd->result = DID_ERROR << 16;
- scb->scsi_cmd->scsi_done(scb->scsi_cmd);
- }
- ips_freescb(ha, scb);
- break;
- default:
- break;
- } /* end case */
- return ;
- }
- #ifndef NO_IPS_CMDLINE
- } /* end if passthru */
- #endif
- if (scb->bus) {
- IPS_HA_LOCK(cpu_flags);
- ha->dcdb_active[scb->bus-1] &= ~(1 << scb->target_id);
- IPS_HA_UNLOCK(cpu_flags);
- }
- /* call back to SCSI layer */
- if (scb->scsi_cmd && scb->scsi_cmd->cmnd[0] != IPS_IOCTL_NEW_COMMAND)
- scb->scsi_cmd->scsi_done(scb->scsi_cmd);
- ips_freescb(ha, scb);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_map_status */
- /* */
- /* Routine Description: */
- /* */
- /* Map ServeRAID error codes to Linux Error Codes */
- /* */
- /****************************************************************************/
- static int
- ips_map_status(ips_ha_t *ha, ips_scb_t *scb, ips_stat_t *sp) {
- int errcode;
- int device_error;
- METHOD_TRACE("ips_map_status", 1);
- if (scb->bus) {
- DEBUG_VAR(2, "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x",
- ips_name,
- ha->host_num,
- scb->scsi_cmd->channel,
- scb->scsi_cmd->target,
- scb->scsi_cmd->lun,
- scb->basic_status,
- scb->extended_status,
- scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0,
- scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0,
- scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0);
- }
- /* default driver error */
- errcode = DID_ERROR;
- device_error = 0;
- switch (scb->basic_status & IPS_GSC_STATUS_MASK) {
- case IPS_CMD_TIMEOUT:
- errcode = DID_TIME_OUT;
- break;
- case IPS_INVAL_OPCO:
- case IPS_INVAL_CMD_BLK:
- case IPS_INVAL_PARM_BLK:
- case IPS_LD_ERROR:
- case IPS_CMD_CMPLT_WERROR:
- break;
- case IPS_PHYS_DRV_ERROR:
- switch (scb->extended_status) {
- case IPS_ERR_SEL_TO:
- if (scb->bus)
- errcode = DID_NO_CONNECT;
- break;
- case IPS_ERR_OU_RUN:
- if ((scb->bus) && (scb->dcdb.transfer_length < scb->data_len)) {
- /* Underrun - set default to no error */
- errcode = DID_OK;
- /* Restrict access to physical DASD */
- if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
- ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) == TYPE_DISK)) {
- /* underflow -- no error */
- /* restrict access to physical DASD */
- errcode = DID_TIME_OUT;
- break;
- }
- } else
- errcode = DID_ERROR;
- break;
- case IPS_ERR_RECOVERY:
- /* don't fail recovered errors */
- if (scb->bus)
- errcode = DID_OK;
- break;
- case IPS_ERR_HOST_RESET:
- case IPS_ERR_DEV_RESET:
- errcode = DID_RESET;
- break;
- case IPS_ERR_CKCOND:
- if (scb->bus) {
- memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info,
- sizeof(scb->scsi_cmd->sense_buffer));
- device_error = 2; /* check condition */
- }
- errcode = DID_OK;
- break;
- default:
- errcode = DID_ERROR;
- break;
- } /* end switch */
- } /* end switch */
- scb->scsi_cmd->result = device_error | (errcode << 16);
- return (1);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_send */
- /* */
- /* Routine Description: */
- /* */
- /* Wrapper for ips_send_cmd */
- /* */
- /****************************************************************************/
- static int
- ips_send(ips_ha_t *ha, ips_scb_t *scb, ips_scb_callback callback) {
- int ret;
- METHOD_TRACE("ips_send", 1);
- scb->callback = callback;
- ret = ips_send_cmd(ha, scb);
- return (ret);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_send_wait */
- /* */
- /* Routine Description: */
- /* */
- /* Send a command to the controller and wait for it to return */
- /* */
- /****************************************************************************/
- static int
- ips_send_wait(ips_ha_t *ha, ips_scb_t *scb, int timeout, int intr) {
- int ret;
- METHOD_TRACE("ips_send_wait", 1);
- ha->waitflag = TRUE;
- ha->cmd_in_progress = scb->cdb[0];
- ret = ips_send(ha, scb, ipsintr_blocking);
- if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
- return (ret);
- ret = ips_wait(ha, timeout, intr);
- return (ret);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_send_cmd */
- /* */
- /* Routine Description: */
- /* */
- /* Map SCSI commands to ServeRAID commands for logical drives */
- /* */
- /****************************************************************************/
- static int
- ips_send_cmd(ips_ha_t *ha, ips_scb_t *scb) {
- int ret;
- char *sp;
- int device_error;
- METHOD_TRACE("ips_send_cmd", 1);
- ret = IPS_SUCCESS;
- if (!scb->scsi_cmd) {
- /* internal command */
- if (scb->bus > 0) {
- /* ServeRAID commands can't be issued */
- /* to real devices -- fail them */
- if ((ha->waitflag == TRUE) &&
- (ha->cmd_in_progress == scb->cdb[0])) {
- ha->waitflag = FALSE;
- }
- return (1);
- }
- #ifndef NO_IPS_CMDLINE
- } else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) {
- #else
- } else if (scb->bus == 0) {
- #endif
- /* command to logical bus -- interpret */
- ret = IPS_SUCCESS_IMM;
- switch (scb->scsi_cmd->cmnd[0]) {
- case ALLOW_MEDIUM_REMOVAL:
- case REZERO_UNIT:
- case ERASE:
- case WRITE_FILEMARKS:
- case SPACE:
- scb->scsi_cmd->result = DID_ERROR << 16;
- break;
- case START_STOP:
- scb->scsi_cmd->result = DID_OK << 16;
- case TEST_UNIT_READY:
- case INQUIRY:
- if (scb->target_id == IPS_ADAPTER_ID) {
- /*
- * Either we have a TUR
- * or we have a SCSI inquiry
- */
- if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY)
- scb->scsi_cmd->result = DID_OK << 16;
- if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
- IPS_SCSI_INQ_DATA inquiry;
- memset(&inquiry, 0, sizeof(IPS_SCSI_INQ_DATA));
- inquiry.DeviceType = IPS_SCSI_INQ_TYPE_PROCESSOR;
- inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED;
- inquiry.Version = IPS_SCSI_INQ_REV2;
- inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2;
- inquiry.AdditionalLength = 31;
- inquiry.Flags[0] = IPS_SCSI_INQ_Address16;
- inquiry.Flags[1] = IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync;
- strncpy(inquiry.VendorId, "IBM ", 8);
- strncpy(inquiry.ProductId, "SERVERAID ", 16);
- strncpy(inquiry.ProductRevisionLevel, "1.00", 4);
- memcpy(scb->scsi_cmd->request_buffer, &inquiry, scb->scsi_cmd->request_bufflen);
- scb->scsi_cmd->result = DID_OK << 16;
- }
- } else {
- scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
- scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
- scb->cmd.logical_info.buffer_addr = cpu_to_le32(VIRT_TO_BUS(&ha->adapt->logical_drive_info));
- scb->cmd.logical_info.reserved = 0;
- scb->cmd.logical_info.reserved2 = 0;
- ret = IPS_SUCCESS;
- }
- break;
- case REQUEST_SENSE:
- ips_reqsen(ha, scb);
- scb->scsi_cmd->result = DID_OK << 16;
- break;
- case READ_6:
- case WRITE_6:
- if (!scb->sg_len) {
- scb->cmd.basic_io.op_code =
- (scb->scsi_cmd->cmnd[0] == READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE;
- } else {
- scb->cmd.basic_io.op_code =
- (scb->scsi_cmd->cmnd[0] == READ_6) ? IPS_CMD_READ_SG : IPS_CMD_WRITE_SG;
- }
- scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
- scb->cmd.basic_io.log_drv = scb->target_id;
- scb->cmd.basic_io.sg_count = scb->sg_len;
- scb->cmd.basic_io.sg_addr = cpu_to_le32(scb->data_busaddr);
- if (scb->cmd.basic_io.lba)
- scb->cmd.basic_io.lba = cpu_to_le32(le32_to_cpu(scb->cmd.basic_io.lba) +
- le16_to_cpu(scb->cmd.basic_io.sector_count));
- else
- scb->cmd.basic_io.lba = (((scb->scsi_cmd->cmnd[1] & 0x1f) << 16) |
- (scb->scsi_cmd->cmnd[2] << 8) |
- (scb->scsi_cmd->cmnd[3]));
- scb->cmd.basic_io.sector_count = cpu_to_le16(scb->data_len / IPS_BLKSIZE);
- if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0)
- scb->cmd.basic_io.sector_count = cpu_to_le16(256);
- scb->cmd.basic_io.reserved = 0;
- ret = IPS_SUCCESS;
- break;
- case READ_10:
- case WRITE_10:
- if (!scb->sg_len) {
- scb->cmd.basic_io.op_code =
- (scb->scsi_cmd->cmnd[0] == READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE;
- } else {
- scb->cmd.basic_io.op_code =
- (scb->scsi_cmd->cmnd[0] == READ_10) ? IPS_CMD_READ_SG : IPS_CMD_WRITE_SG;
- }
- scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
- scb->cmd.basic_io.log_drv = scb->target_id;
- scb->cmd.basic_io.sg_count = scb->sg_len;
- scb->cmd.basic_io.sg_addr = cpu_to_le32(scb->data_busaddr);
- if (scb->cmd.basic_io.lba)
- scb->cmd.basic_io.lba = cpu_to_le32(le32_to_cpu(scb->cmd.basic_io.lba) +
- le16_to_cpu(scb->cmd.basic_io.sector_count));
- else
- scb->cmd.basic_io.lba = ((scb->scsi_cmd->cmnd[2] << 24) |
- (scb->scsi_cmd->cmnd[3] << 16) |
- (scb->scsi_cmd->cmnd[4] << 8) |
- scb->scsi_cmd->cmnd[5]);
- scb->cmd.basic_io.sector_count = cpu_to_le16(scb->data_len / IPS_BLKSIZE);
- scb->cmd.basic_io.reserved = 0;
- if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) {
- /*
- * This is a null condition
- * we don't have to do anything
- * so just return
- */
- scb->scsi_cmd->result = DID_OK << 16;
- } else
- ret = IPS_SUCCESS;
- break;
- case RESERVE:
- case RELEASE:
- scb->scsi_cmd->result = DID_OK << 16;
- break;
- case MODE_SENSE:
- scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
- scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
- scb->cmd.basic_io.sg_addr = cpu_to_le32(VIRT_TO_BUS(ha->enq));
- ret = IPS_SUCCESS;
- break;
- case READ_CAPACITY:
- scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
- scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
- scb->cmd.logical_info.buffer_addr = cpu_to_le32(VIRT_TO_BUS(&ha->adapt->logical_drive_info));
- scb->cmd.logical_info.reserved = 0;
- scb->cmd.logical_info.reserved2 = 0;
- scb->cmd.logical_info.reserved3 = 0;
- ret = IPS_SUCCESS;
- break;
- case SEND_DIAGNOSTIC:
- case REASSIGN_BLOCKS:
- case FORMAT_UNIT:
- case SEEK_10:
- case VERIFY:
- case READ_DEFECT_DATA:
- case READ_BUFFER:
- case WRITE_BUFFER:
- scb->scsi_cmd->result = DID_OK << 16;
- break;
- default:
- /* Set the Return Info to appear like the Command was */
- /* attempted, a Check Condition occurred, and Sense */
- /* Data indicating an Invalid CDB OpCode is returned. */
- sp = (char *) scb->scsi_cmd->sense_buffer;
- memset(sp, 0, sizeof(scb->scsi_cmd->sense_buffer));
-
- sp[0] = 0x70; /* Error Code */
- sp[2] = ILLEGAL_REQUEST; /* Sense Key 5 Illegal Req. */
- sp[7] = 0x0A; /* Additional Sense Length */
- sp[12] = 0x20; /* ASC = Invalid OpCode */
- sp[13] = 0x00; /* ASCQ */
-
- device_error = 2; /* Indicate Check Condition */
- scb->scsi_cmd->result = device_error | (DID_OK << 16);
- break;
- } /* end switch */
- } /* end if */
- if (ret == IPS_SUCCESS_IMM)
- return (ret);
- /* setup DCDB */
- if (scb->bus > 0) {
- if (!scb->sg_len)
- scb->cmd.dcdb.op_code = IPS_CMD_DCDB;
- else
- scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG;
- /* If we already know the Device is Not there, no need to attempt a Command */
- /* This also protects an NT FailOver Controller from getting CDB's sent to it */
- if ( ha->conf->dev[scb->bus-1][scb->target_id].ucState == 0 ) {
- scb->scsi_cmd->result = DID_NO_CONNECT << 16;
- return (IPS_SUCCESS_IMM);
- }
- ha->dcdb_active[scb->bus-1] |= (1 << scb->target_id);
- scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
- scb->cmd.dcdb.dcdb_address = cpu_to_le32(VIRT_TO_BUS(&scb->dcdb));
- scb->cmd.dcdb.reserved = 0;
- scb->cmd.dcdb.reserved2 = 0;
- scb->cmd.dcdb.reserved3 = 0;
- scb->dcdb.device_address = ((scb->bus - 1) << 4) | scb->target_id;
- scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
- if (scb->timeout) {
- if (scb->timeout <= 10)
- scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
- else if (scb->timeout <= 60)
- scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
- else
- scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
- }
- if (!(scb->dcdb.cmd_attribute & IPS_TIMEOUT20M))
- scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
- scb->dcdb.sense_length = sizeof(scb->scsi_cmd->sense_buffer);
- scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
- scb->dcdb.sg_count = scb->sg_len;
- scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
- memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
- }
- return ((*ha->func.issue)(ha, scb));
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_chk_status */
- /* */
- /* Routine Description: */
- /* */
- /* Check the status of commands to logical drives */
- /* */
- /****************************************************************************/
- static void
- ips_chkstatus(ips_ha_t *ha, IPS_STATUS *pstatus) {
- ips_scb_t *scb;
- ips_stat_t *sp;
- u_int8_t basic_status;
- u_int8_t ext_status;
- int errcode;
- METHOD_TRACE("ips_chkstatus", 1);
- scb = &ha->scbs[pstatus->fields.command_id];
- scb->basic_status = basic_status = pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK;
- scb->extended_status = ext_status = pstatus->fields.extended_status;
- sp = &ha->sp;
- sp->residue_len = 0;
- sp->scb_addr = (void *) scb;