aachba.c
来自「linux 内核源代码」· C语言 代码 · 共 2,197 行 · 第 1/5 页
C
2,197 行
(cmd->cmnd[7] << 16) | (cmd->cmnd[8] << 8) | cmd->cmnd[9]; cmnd_count = (cmd->cmnd[10] << 24) | (cmd->cmnd[11] << 16) | (cmd->cmnd[12] << 8) | cmd->cmnd[13]; } else if (cmd->cmnd[0] == WRITE_12) { cmnd_lba = ((u64)cmd->cmnd[2] << 24) | (cmd->cmnd[3] << 16) | (cmd->cmnd[4] << 8) | cmd->cmnd[5]; cmnd_count = (cmd->cmnd[6] << 24) | (cmd->cmnd[7] << 16) | (cmd->cmnd[8] << 8) | cmd->cmnd[9]; } else if (cmd->cmnd[0] == WRITE_10) { cmnd_lba = ((u64)cmd->cmnd[2] << 24) | (cmd->cmnd[3] << 16) | (cmd->cmnd[4] << 8) | cmd->cmnd[5]; cmnd_count = (cmd->cmnd[7] << 8) | cmd->cmnd[8]; } else continue; if (((cmnd_lba + cmnd_count) < lba) || (count && ((lba + count) < cmnd_lba))) continue; ++active; break; } spin_unlock_irqrestore(&sdev->list_lock, flags); /* * Yield the processor (requeue for later) */ if (active) return SCSI_MLQUEUE_DEVICE_BUSY; aac = (struct aac_dev *)scsicmd->device->host->hostdata; if (aac->in_reset) return SCSI_MLQUEUE_HOST_BUSY; /* * Allocate and initialize a Fib */ if (!(cmd_fibcontext = aac_fib_alloc(aac))) return SCSI_MLQUEUE_HOST_BUSY; aac_fib_init(cmd_fibcontext); synchronizecmd = fib_data(cmd_fibcontext); synchronizecmd->command = cpu_to_le32(VM_ContainerConfig); synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE); synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd)); synchronizecmd->count = cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data)); /* * Now send the Fib to the adapter */ status = aac_fib_send(ContainerCommand, cmd_fibcontext, sizeof(struct aac_synchronize), FsaNormal, 0, 1, (fib_callback)synchronize_callback, (void *)scsicmd); /* * Check that the command queued to the controller */ if (status == -EINPROGRESS) { scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; return 0; } printk(KERN_WARNING "aac_synchronize: aac_fib_send failed with status: %d.\n", status); aac_fib_complete(cmd_fibcontext); aac_fib_free(cmd_fibcontext); return SCSI_MLQUEUE_HOST_BUSY;}/** * aac_scsi_cmd() - Process SCSI command * @scsicmd: SCSI command block * * Emulate a SCSI command and queue the required request for the * aacraid firmware. */ int aac_scsi_cmd(struct scsi_cmnd * scsicmd){ u32 cid; struct Scsi_Host *host = scsicmd->device->host; struct aac_dev *dev = (struct aac_dev *)host->hostdata; struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev; if (fsa_dev_ptr == NULL) return -1; /* * If the bus, id or lun is out of range, return fail * Test does not apply to ID 16, the pseudo id for the controller * itself. */ cid = scmd_id(scsicmd); if (cid != host->this_id) { if (scmd_channel(scsicmd) == CONTAINER_CHANNEL) { if((cid >= dev->maximum_num_containers) || (scsicmd->device->lun != 0)) { scsicmd->result = DID_NO_CONNECT << 16; scsicmd->scsi_done(scsicmd); return 0; } /* * If the target container doesn't exist, it may have * been newly created */ if ((fsa_dev_ptr[cid].valid & 1) == 0) { switch (scsicmd->cmnd[0]) { case SERVICE_ACTION_IN: if (!(dev->raw_io_interface) || !(dev->raw_io_64) || ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) break; case INQUIRY: case READ_CAPACITY: case TEST_UNIT_READY: if (dev->in_reset) return -1; return _aac_probe_container(scsicmd, aac_probe_container_callback2); default: break; } } } else { /* check for physical non-dasd devices */ if ((dev->nondasd_support == 1) || expose_physicals) { if (dev->in_reset) return -1; return aac_send_srb_fib(scsicmd); } else { scsicmd->result = DID_NO_CONNECT << 16; scsicmd->scsi_done(scsicmd); return 0; } } } /* * else Command for the controller itself */ else if ((scsicmd->cmnd[0] != INQUIRY) && /* only INQUIRY & TUR cmnd supported for controller */ (scsicmd->cmnd[0] != TEST_UNIT_READY)) { 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 *) &dev->fsa_dev[cid].sense_data, ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer)) ? sizeof(scsicmd->sense_buffer) : sizeof(dev->fsa_dev[cid].sense_data)); scsicmd->scsi_done(scsicmd); return 0; } /* Handle commands here that don't really require going out to the adapter */ switch (scsicmd->cmnd[0]) { case INQUIRY: { struct inquiry_data inq_data; dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid)); memset(&inq_data, 0, sizeof (struct inquiry_data)); if (scsicmd->cmnd[1] & 0x1 ) { char *arr = (char *)&inq_data; /* EVPD bit set */ arr[0] = (scmd_id(scsicmd) == host->this_id) ? INQD_PDT_PROC : INQD_PDT_DA; if (scsicmd->cmnd[2] == 0) { /* supported vital product data pages */ arr[3] = 2; arr[4] = 0x0; arr[5] = 0x80; arr[1] = scsicmd->cmnd[2]; aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; } else if (scsicmd->cmnd[2] == 0x80) { /* unit serial number page */ arr[3] = setinqserial(dev, &arr[4], scmd_id(scsicmd)); arr[1] = scsicmd->cmnd[2]; aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data)); return aac_get_container_serial(scsicmd); } else { /* vpd page not implemented */ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; set_sense((u8 *) &dev->fsa_dev[cid].sense_data, ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD, ASENCODE_NO_SENSE, 0, 7, 2, 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; } inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */ inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ inq_data.inqd_len = 31; /*Format for "pad2" is RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ inq_data.inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */ /* * Set the Vendor, Product, and Revision Level * see: <vendor>.c i.e. aac.c */ 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)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; } if (dev->in_reset) return -1; setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type); inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data)); return aac_get_container_name(scsicmd); } case SERVICE_ACTION_IN: if (!(dev->raw_io_interface) || !(dev->raw_io_64) || ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) break; { u64 capacity; char cp[13]; dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n")); capacity = fsa_dev_ptr[cid].size - 1; cp[0] = (capacity >> 56) & 0xff; cp[1] = (capacity >> 48) & 0xff; cp[2] = (capacity >> 40) & 0xff; cp[3] = (capacity >> 32) & 0xff; cp[4] = (capacity >> 24) & 0xff; cp[5] = (capacity >> 16) & 0xff; cp[6] = (capacity >> 8) & 0xff; cp[7] = (capacity >> 0) & 0xff; cp[8] = 0; cp[9] = 0; cp[10] = 2; cp[11] = 0; cp[12] = 0; aac_internal_transfer(scsicmd, cp, 0, min_t(size_t, scsicmd->cmnd[13], sizeof(cp))); if (sizeof(cp) < scsicmd->cmnd[13]) { unsigned int len, offset = sizeof(cp); memset(cp, 0, offset); do { len = min_t(size_t, scsicmd->cmnd[13] - offset, sizeof(cp)); aac_internal_transfer(scsicmd, cp, offset, len); } while ((offset += len) < scsicmd->cmnd[13]); } /* Do not cache partition table for arrays */ scsicmd->device->removable = 1; scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; } case READ_CAPACITY: { u32 capacity; char cp[8]; dprintk((KERN_DEBUG "READ CAPACITY command.\n")); if (fsa_dev_ptr[cid].size <= 0x100000000ULL) capacity = fsa_dev_ptr[cid].size - 1; else capacity = (u32)-1; cp[0] = (capacity >> 24) & 0xff; cp[1] = (capacity >> 16) & 0xff; cp[2] = (capacity >> 8) & 0xff; cp[3] = (capacity >> 0) & 0xff; cp[4] = 0; cp[5] = 0; cp[6] = 2; cp[7] = 0; aac_internal_transfer(scsicmd, cp, 0, sizeof(cp)); /* Do not cache partition table for arrays */ scsicmd->device->removable = 1; scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; } case MODE_SENSE: { char mode_buf[7]; int mode_buf_length = 4; dprintk((KERN_DEBUG "MODE SENSE command.\n")); mode_buf[0] = 3; /* Mode data length */ mode_buf[1] = 0; /* Medium type - default */ mode_buf[2] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected bit 4: 0/1 = FUA enabled */ if (dev->raw_io_interface) mode_buf[2] = 0x10; mode_buf[3] = 0; /* Block descriptor length */ if (((scsicmd->cmnd[2] & 0x3f) == 8) || ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) { mode_buf[0] = 6; mode_buf[4] = 8; mode_buf[5] = 1; mode_buf[6] = 0x04; /* WCE */ mode_buf_length = 7; if (mode_buf_length > scsicmd->cmnd[4]) mode_buf_length = scsicmd->cmnd[4]; } aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; } case MODE_SENSE_10: { char mode_buf[11]; int mode_buf_length = 8; dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n")); mode_buf[0] = 0; /* Mode data length (MSB) */ mode_buf[1] = 6; /* Mode data length (LSB) */ mode_buf[2] = 0; /* Medium type - default */ mode_buf[3] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected bit 4: 0/1 = FUA enabled */ if (dev->raw_io_interface) mode_buf[3] = 0x10; mode_buf[4] = 0; /* reserved */ mode_buf[5] = 0; /* reserved */ mode_buf[6] = 0; /* Block descriptor length (MSB) */ mode_buf[7] = 0; /* Block descriptor length (LSB) */ if (((scsicmd->cmnd[2] & 0x3f) == 8) || ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) { mode_buf[1] = 9; mode_buf[8] = 8; mode_buf[9] = 1; mode_buf[10] = 0x04; /* WCE */ mode_buf_length = 11; if (mode_buf_length > scsicmd->cmnd[8]) mode_buf_length = scsicmd->cmnd[8]; } aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; } case REQUEST_SENSE: dprintk((KERN_DEBUG "REQUEST SENSE command.\n")); 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; scsicmd->scsi_done(scsicmd); return 0; case ALLOW_MEDIUM_REMOVAL: dprintk((KERN_DEBUG "LOCK command.\n")); if (scsicmd->cmnd[4]) fsa_dev_ptr[cid].locked = 1; else fsa_dev_ptr[cid].locked = 0; scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; /* * These commands are all No-Ops */ case TEST_UNIT_READY: 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; } switch (scsicmd->cmnd[0]) { case READ_6: case READ_10: case READ_12: case READ_16: if (dev->in_reset) return -1; /* * Hack to keep track of ordinal number of the device that * corresponds to a container. Needed to convert * containers to /dev/sd device names */ if (scsicmd->request->rq_disk)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?