X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fscsi%2Faacraid%2Faachba.c;h=aa4e77c252735c593e523ae4a9f516045b674733;hb=2a5f2e3e6cd1ce9fb3f8b186b6bc9aa1f1497a92;hp=c05092fd3a9dff7bfb3197639d0b5908b6a3d5b0;hpb=f6866fecd6fd8e44a6715da09844a4fd1b8484da;p=linux-2.6 diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index c05092fd3a..aa4e77c252 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include /* For flush_kernel_dcache_page */ @@ -205,7 +204,7 @@ MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health" int aac_check_reset = 1; module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the" +MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the" " adapter. a value of -1 forces the reset to adapters programmed to" " ignore it."); @@ -379,24 +378,6 @@ int aac_get_containers(struct aac_dev *dev) return status; } -static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigned int offset, unsigned int len) -{ - void *buf; - int transfer_len; - struct scatterlist *sg = scsi_sglist(scsicmd); - - buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; - transfer_len = min(sg->length, len + offset); - - transfer_len -= offset; - if (buf && transfer_len > 0) - memcpy(buf + offset, data, transfer_len); - - flush_kernel_dcache_page(kmap_atomic_to_page(buf - sg->offset)); - kunmap_atomic(buf - sg->offset, KM_IRQ0); - -} - static void get_container_name_callback(void *context, struct fib * fibptr) { struct aac_get_name_resp * get_name_reply; @@ -419,14 +400,17 @@ static void get_container_name_callback(void *context, struct fib * fibptr) while (*sp == ' ') ++sp; if (*sp) { + struct inquiry_data inq; char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)]; int count = sizeof(d); char *dp = d; do { *dp++ = (*sp) ? *sp++ : ' '; } while (--count > 0); - aac_internal_transfer(scsicmd, d, - offsetof(struct inquiry_data, inqd_pid), sizeof(d)); + + scsi_sg_copy_to_buffer(scsicmd, &inq, sizeof(inq)); + memcpy(inq.inqd_pid, d, sizeof(d)); + scsi_sg_copy_from_buffer(scsicmd, &inq, sizeof(inq)); } } @@ -514,6 +498,11 @@ static void _aac_probe_container2(void * context, struct fib * fibptr) (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) { fsa_dev_ptr->valid = 1; + /* sense_key holds the current state of the spin-up */ + if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY)) + fsa_dev_ptr->sense_data.sense_key = NOT_READY; + else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY) + fsa_dev_ptr->sense_data.sense_key = NO_SENSE; fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol); fsa_dev_ptr->size = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + @@ -811,7 +800,7 @@ static void get_container_serial_callback(void *context, struct fib * fibptr) sp[2] = 0; sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X", le32_to_cpu(get_serial_reply->uid)); - aac_internal_transfer(scsicmd, sp, 0, sizeof(sp)); + scsi_sg_copy_from_buffer(scsicmd, sp, sizeof(sp)); } scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; @@ -1331,7 +1320,7 @@ int aac_get_adapter_info(struct aac_dev* dev) tmp>>24,(tmp>>16)&0xff,tmp&0xff, le32_to_cpu(dev->adapter_info.biosbuild)); buffer[0] = '\0'; - if (aac_show_serial_number( + if (aac_get_serial_number( shost_to_class(dev->scsi_host_ptr), buffer)) printk(KERN_INFO "%s%d: serial %s", dev->name, dev->id, buffer); @@ -1525,20 +1514,35 @@ static void io_callback(void *context, struct fib * fibptr) scsi_dma_unmap(scsicmd); readreply = (struct aac_read_reply *)fib_data(fibptr); - if (le32_to_cpu(readreply->status) == ST_OK) - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - else { + switch (le32_to_cpu(readreply->status)) { + case ST_OK: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | + SAM_STAT_GOOD; + dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE; + break; + case ST_NOT_READY: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | + SAM_STAT_CHECK_CONDITION; + set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY, + SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0); + memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, + min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), + SCSI_SENSE_BUFFERSIZE)); + break; + default: #ifdef AAC_DETAILED_STATUS_INFO printk(KERN_WARNING "io_callback: io failed, status = %d\n", le32_to_cpu(readreply->status)); #endif - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | + SAM_STAT_CHECK_CONDITION; set_sense(&dev->fsa_dev[cid].sense_data, HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); + break; } aac_fib_complete(fibptr); aac_fib_free(fibptr); @@ -1879,6 +1883,84 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd) return SCSI_MLQUEUE_HOST_BUSY; } +static void aac_start_stop_callback(void *context, struct fib *fibptr) +{ + struct scsi_cmnd *scsicmd = context; + + if (!aac_valid_context(scsicmd, fibptr)) + return; + + BUG_ON(fibptr == NULL); + + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; + + aac_fib_complete(fibptr); + aac_fib_free(fibptr); + scsicmd->scsi_done(scsicmd); +} + +static int aac_start_stop(struct scsi_cmnd *scsicmd) +{ + int status; + struct fib *cmd_fibcontext; + struct aac_power_management *pmcmd; + struct scsi_device *sdev = scsicmd->device; + struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata; + + if (!(aac->supplement_adapter_info.SupportedOptions2 & + AAC_OPTION_POWER_MANAGEMENT)) { + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | + SAM_STAT_GOOD; + scsicmd->scsi_done(scsicmd); + return 0; + } + + if (aac->in_reset) + return SCSI_MLQUEUE_HOST_BUSY; + + /* + * Allocate and initialize a Fib + */ + cmd_fibcontext = aac_fib_alloc(aac); + if (!cmd_fibcontext) + return SCSI_MLQUEUE_HOST_BUSY; + + aac_fib_init(cmd_fibcontext); + + pmcmd = fib_data(cmd_fibcontext); + pmcmd->command = cpu_to_le32(VM_ContainerConfig); + pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT); + /* Eject bit ignored, not relevant */ + pmcmd->sub = (scsicmd->cmnd[4] & 1) ? + cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT); + pmcmd->cid = cpu_to_le32(sdev_id(sdev)); + pmcmd->parm = (scsicmd->cmnd[1] & 1) ? + cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0; + + /* + * Now send the Fib to the adapter + */ + status = aac_fib_send(ContainerCommand, + cmd_fibcontext, + sizeof(struct aac_power_management), + FsaNormal, + 0, 1, + (fib_callback)aac_start_stop_callback, + (void *)scsicmd); + + /* + * Check that the command queued to the controller + */ + if (status == -EINPROGRESS) { + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; + return 0; + } + + aac_fib_complete(cmd_fibcontext); + aac_fib_free(cmd_fibcontext); + return SCSI_MLQUEUE_HOST_BUSY; +} + /** * aac_scsi_cmd() - Process SCSI command * @scsicmd: SCSI command block @@ -1915,7 +1997,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) * If the target container doesn't exist, it may have * been newly created */ - if ((fsa_dev_ptr[cid].valid & 1) == 0) { + if (((fsa_dev_ptr[cid].valid & 1) == 0) || + (fsa_dev_ptr[cid].sense_data.sense_key == + NOT_READY)) { switch (scsicmd->cmnd[0]) { case SERVICE_ACTION_IN: if (!(dev->raw_io_interface) || @@ -1986,8 +2070,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) arr[4] = 0x0; arr[5] = 0x80; arr[1] = scsicmd->cmnd[2]; - aac_internal_transfer(scsicmd, &inq_data, 0, - sizeof(inq_data)); + scsi_sg_copy_from_buffer(scsicmd, &inq_data, + sizeof(inq_data)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; } else if (scsicmd->cmnd[2] == 0x80) { @@ -1995,8 +2079,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) arr[3] = setinqserial(dev, &arr[4], scmd_id(scsicmd)); arr[1] = scsicmd->cmnd[2]; - aac_internal_transfer(scsicmd, &inq_data, 0, - sizeof(inq_data)); + scsi_sg_copy_from_buffer(scsicmd, &inq_data, + sizeof(inq_data)); return aac_get_container_serial(scsicmd); } else { /* vpd page not implemented */ @@ -2027,7 +2111,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) if (cid == host->this_id) { setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types)); inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */ - aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data)); + scsi_sg_copy_from_buffer(scsicmd, &inq_data, + sizeof(inq_data)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; @@ -2036,7 +2121,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) return -1; setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type); inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ - aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data)); + scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); return aac_get_container_name(scsicmd); } case SERVICE_ACTION_IN: @@ -2047,6 +2132,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) { u64 capacity; char cp[13]; + unsigned int alloc_len; dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n")); capacity = fsa_dev_ptr[cid].size - 1; @@ -2063,18 +2149,16 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) cp[10] = 2; cp[11] = 0; cp[12] = 0; - aac_internal_transfer(scsicmd, cp, 0, - min_t(size_t, scsicmd->cmnd[13], sizeof(cp))); - if (sizeof(cp) < scsicmd->cmnd[13]) { - unsigned int len, offset = sizeof(cp); - memset(cp, 0, offset); - do { - len = min_t(size_t, scsicmd->cmnd[13] - offset, - sizeof(cp)); - aac_internal_transfer(scsicmd, cp, offset, len); - } while ((offset += len) < scsicmd->cmnd[13]); - } + alloc_len = ((scsicmd->cmnd[10] << 24) + + (scsicmd->cmnd[11] << 16) + + (scsicmd->cmnd[12] << 8) + scsicmd->cmnd[13]); + + alloc_len = min_t(size_t, alloc_len, sizeof(cp)); + scsi_sg_copy_from_buffer(scsicmd, cp, alloc_len); + if (alloc_len < scsi_bufflen(scsicmd)) + scsi_set_resid(scsicmd, + scsi_bufflen(scsicmd) - alloc_len); /* Do not cache partition table for arrays */ scsicmd->device->removable = 1; @@ -2104,11 +2188,11 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) cp[5] = 0; cp[6] = 2; cp[7] = 0; - aac_internal_transfer(scsicmd, cp, 0, sizeof(cp)); + scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp)); /* Do not cache partition table for arrays */ scsicmd->device->removable = 1; - - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | + SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; @@ -2139,7 +2223,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) if (mode_buf_length > scsicmd->cmnd[4]) mode_buf_length = scsicmd->cmnd[4]; } - aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length); + scsi_sg_copy_from_buffer(scsicmd, mode_buf, mode_buf_length); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); @@ -2174,7 +2258,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) if (mode_buf_length > scsicmd->cmnd[8]) mode_buf_length = scsicmd->cmnd[8]; } - aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length); + scsi_sg_copy_from_buffer(scsicmd, mode_buf, mode_buf_length); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); @@ -2203,15 +2287,32 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) * These commands are all No-Ops */ case TEST_UNIT_READY: + if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) { + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | + SAM_STAT_CHECK_CONDITION; + set_sense(&dev->fsa_dev[cid].sense_data, + NOT_READY, SENCODE_BECOMING_READY, + ASENCODE_BECOMING_READY, 0, 0); + memcpy(scsicmd->sense_buffer, + &dev->fsa_dev[cid].sense_data, + min_t(size_t, + sizeof(dev->fsa_dev[cid].sense_data), + SCSI_SENSE_BUFFERSIZE)); + scsicmd->scsi_done(scsicmd); + return 0; + } + /* FALLTHRU */ case RESERVE: case RELEASE: case REZERO_UNIT: case REASSIGN_BLOCKS: case SEEK_10: - case START_STOP: scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; + + case START_STOP: + return aac_start_stop(scsicmd); } switch (scsicmd->cmnd[0])