📄 scsi_target.c
字号:
{ err = cmd[4] * BLOCKSIZE; if (err == 0) err = 256 * BLOCKSIZE;# ifdef DEBUG_ALLOCN_LEN printk("get_allocation_length: READ_6/WRITE_6 length %d\n", err);# endif break; }# endif default: { printk("get_allocation_length: unknown command 0x%02x\n", cmd[0]); break; } } return err;}#endif /* if !defined(DISKIO) || !defined(TRUST_CDB) */# if defined (FILEIO) || defined (MEMORYIO)/* * get_inquiry_response: This function fills in the buffer to respond to * a received SCSI INQUIRY. This function is relevant when the emulator * is responding to commands itself and not transmitting it onto a SCSI * HBA attached to the system * INPUT: Scsi_Request ptr to the inquiry, length of expected response * OUTPUT: 0 if everything is okay, < 0 if there is trouble */static int/* Bjorn Thordarson, 9-May-2004 *//*****get_inquiry_response(Scsi_Request * req, int len)*****/get_inquiry_response(Scsi_Request * req, int len, int type){ __u8 *inq; __u8 *ptr, local_buffer[36];/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 __u8 *buffer = (void *)sg_dma_address((struct scatterlist *) req->sr_buffer);#else __u8 *buffer = ((struct scatterlist *) req->sr_buffer)->address;#endif /* SPC-2 says in section 7.3.2 on page 82: * "The standard INQUIRY data shall contain at least 36 bytes." */ if (len >= 36) { /* caller's buffer is big enough to hold all 36 bytes */ ptr = buffer; memset(buffer, 0x00, len); } else { /* fill a local 36-byte buffer */ ptr = local_buffer; memset(local_buffer, 0x00, 36); } /* Bjorn Thordarson, 9-May-2004 */ /***** ptr[0] = TYPE_DISK; *****/ ptr[0] = type; ptr[2] = 4; /* Device complies to this standard - SPC-2 */ ptr[3] = 2; /* data in format specified in this standard */ ptr[4] = 31; /* n - 4 = 35 - 4 = 31 for full 36 byte data */ ptr[6] = 0x80; /* BQue = 1 basic task management supported */ /* SPC-2 says in section 7.3.2 on page 86: * "ASCII data fields shall contain only graphic codes (i.e., code * values 20h through 7Eh). Left-aligned fields shall place any * unused bytes at the end of the field (highest offset) and the * unused bytes shall be filled with space characters (20h)." */ /* 8 byte ASCII Vendor Identification of the target - left aligned */ memcpy(&ptr[8], "UNH-IOL ", 8); /* 16 byte ASCII Product Identification of the target - left aligned */# if defined (FILEIO) memcpy(&ptr[16], "file-mode target", 16);# else memcpy(&ptr[16], "in-memory target", 16);#endif /* 4 byte ASCII Product Revision Level of the target - left aligned */ memcpy(&ptr[32], "1.2 ", 4); if (len < 36) { /* fill as much as possible of caller's too-small buffer */ memcpy(buffer, ptr, len); } req->sr_result = DID_OK << 16; if (req->sr_allowed == 1) {/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 inq = (void *)sg_dma_address((struct scatterlist *) req->sr_buffer);#else inq = ((struct scatterlist *) req->sr_buffer)->address;#endif inq[0] = 0x7f; } return 0;}/* * get_read_capacity_response: This function fills up the buffer to * respond to a received READ_CAPACITY. This function is relevant when * the emulator is responding to the commands. * INPUT: Scsi_Request pointer to the READ_CAPACITY * OUTPUT: 0 if everything is okay, < 0 if there is trouble */static int/* Bjorn Thordarson, 9-May-2004 *//*****get_read_capacity_response(Scsi_Request * req)*****/get_read_capacity_response(Target_Scsi_Cmnd *cmnd){ __u32 blocksize = BLOCKSIZE, nblocks; __u8 *buffer;/* RDR */ nblocks = FILESIZE;#ifdef FILEIO if (!down_interruptible(&target_map_sem)) { if (cmnd->target_id >= MAX_TARGETS || cmnd->lun >= MAX_LUNS || !target_map[cmnd->target_id][cmnd->lun].in_use) { printk("%s target id %u lun %u not in use\n", current->comm, cmnd->target_id, cmnd->lun); up(&target_map_sem); return -1; } nblocks = target_map[cmnd->target_id][cmnd->lun].max_blocks; up(&target_map_sem); }#endif/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 /***** buffer = (void *)sg_dma_address((struct scatterlist *)req->sr_buffer); *****/ buffer = (void *)sg_dma_address((struct scatterlist *)cmnd->req->sr_buffer);#else /***** buffer = ((struct scatterlist *)req->sr_buffer)->address; *****/ buffer = ((struct scatterlist *)cmnd->req->sr_buffer)->address;#endif /* Bjorn Thordarson, 9-May-2004 -- end -- */ memset(buffer, 0x00, READ_CAP_LEN); /* last block on the disk is (nblocks-1) */ buffer[0] = ((nblocks - 1) >> (BYTE * 3)) & 0xFF; buffer[1] = ((nblocks - 1) >> (BYTE * 2)) & 0xFF; buffer[2] = ((nblocks - 1) >> (BYTE)) & 0xFF; buffer[3] = (nblocks - 1) & 0xFF; buffer[4] = (blocksize >> (BYTE * 3)) & 0xFF; buffer[5] = (blocksize >> (BYTE * 2)) & 0xFF; buffer[6] = (blocksize >> BYTE) & 0xFF; buffer[7] = blocksize & 0xFF; /* Bjorn Thordarson, 9-May-2004 */ /***** req->sr_result = DID_OK << 16; *****/ cmnd->req->sr_result = DID_OK << 16; return 0;}/* RDR */#ifdef FILEIO/* Bjorn Thordarson, 8-May-2004 -- start -- *//* get_mode_sense_response2: This function fills up the buffer to * respond to a received MODE_SENSE. This function is relevant when * the emulator is responding to the commands. * INPUT: Scsi_Request pointer to the MODE_SENSE * OUTPUT: 0 if everything is okay, < 0 if there is trouble */struct iscsi_sense_data { u16 length; u8 data[0];} __packed;static intget_mode_sense_response2(Scsi_Request * req, u8 sense_key, u8 asc, u8 ascq){ struct iscsi_sense_data *sense;/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 __u8 *buffer = (void *)sg_dma_address((struct scatterlist *) req->sr_buffer);#else __u8 *buffer = ((struct scatterlist *) req->sr_buffer)->address;#endif sense = (struct iscsi_sense_data *) buffer; sense->length = cpu_to_be16(14); memset(sense->data, 0, 14); sense->data[0] = 0xf0; sense->data[2] = sense_key; sense->data[7] = 6; // Additional sense length sense->data[12] = asc; sense->data[13] = ascq; req->sr_result = DID_OK << 16; return 0;}/* Bjorn Thordarson, 9-May-2004 -- end -- */#endif/* cdeng August 24 2002 * get_mode_sense_response: This function fills up the buffer to * respond to a received MODE_SENSE. This function is relevant when * the emulator is responding to the commands. * INPUT: Scsi_Request pointer to the MODE_SENSE * OUTPUT: 0 if everything is okay, < 0 if there is trouble */static intget_mode_sense_response(Scsi_Request * req, __u32 len){/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 __u8 *buffer = (void *)sg_dma_address((struct scatterlist *) req->sr_buffer);#else __u8 *buffer = ((struct scatterlist *) req->sr_buffer)->address;#endif memset(buffer, 0x00, len); buffer[0] = 0x0b; // no. of bytes that follow == 11 buffer[3] = 0x08; // block descriptor length buffer[10] = 0x02; // density code and block length req->sr_result = DID_OK << 16; return 0;}#endif /* defined (FILEIO) || defined (MEMORYIO) */#ifndef DISKIO/* cdeng August 24 2002 * get_report_luns_response: This function fills up the buffer to * respond to a received REPORT_LUNS. This function is relevant when * the emulator is responding to the commands. * INPUT: Scsi_Request pointer to the REPORT_LUNS * OUTPUT: 0 if everything is okay, < 0 if there is trouble */static intget_report_luns_response(Target_Scsi_Cmnd *cmnd, __u32 len){ int i; __u8 *limit, *next_slot;/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 /* Bjorn Thordarson, 9-May-2004 */ /***** __u8 *buffer = (void *)sg_dma_address((struct scatterlist *) req->sr_buffer); *****/ __u8 *buffer = (void *)sg_dma_address((struct scatterlist *) cmnd->req->sr_buffer);#else /* Bjorn Thordarson, 9-May-2004 */ /***** __u8 *buffer = ((struct scatterlist *) req->sr_buffer)->address; *****/ __u8 *buffer = ((struct scatterlist *) cmnd->req->sr_buffer)->address;#endif next_slot = buffer + 8; /* first lun goes here */ limit = next_slot + len; /* address after end of entire list */ memset(buffer, 0x00, len + 8); /* SAM-2, section 4.12.2 LUN 0 address * "To address the LUN 0 of a SCSI device the peripheral device * address method shall be used." * * What this means is that whenever the LUN is 0, the full 8 bytes of * the LUN field in the iscsi PDU will also be 0. Because we have * already zeroed out the entire buffer above, * we don't need to do anything else here for lun 0. */ if (cmnd->target_id < MAX_TARGETS) { if (!down_interruptible(&target_map_sem)) { for (i = 0; i < MAX_LUNS && next_slot < limit; i++) { if (target_map[cmnd->target_id][i].in_use) { pack_lun(i, 0, next_slot); next_slot += 8;; } } up(&target_map_sem); } } /* lun list length */ ((__u32 *)buffer)[0] = cpu_to_be32(len);# ifdef DEBUG_HANDLE_CMD /* dump out the complete REPORT LUNS response buffer */ dump_buffer(buffer, len + 8);# endif /* change status */ cmnd->state = ST_DONE; cmnd->req->sr_result = DID_OK << 16; return 0;}#endif/* * hand_to_front_end: the scsi command has been tackled by the mid-level * and is now ready to be handed off to the front-end either because it * is done or because data is needed to process this command. * This function is separated only because it makes * the main code a lot cleaner. * INPUT: Scsi_Cmnd that needs to be handed off * OUTPUT: 0 if everything is okay, < 0 if there is trouble */static inthand_to_front_end(Target_Scsi_Cmnd * the_command){ Scsi_Target_Device *curr_device;# ifdef GENERICIO __u8 *temp;# endif /* get the device template corresponding to the device_id */ for (curr_device = target_data.st_device_list; curr_device != NULL; curr_device = curr_device->next) { if (curr_device->id == the_command->dev_id) break; } if (curr_device == NULL) { /* huh - should not get here */ /* * That there is not a device with this id may mean * one of two things - there has been a mistake or * that the device is no longer there. For now, the * former is more probable */ printk("%s hand_to_front_end: no device with id %llu\n", current->comm, the_command->dev_id); return -1; } /* * In the time that the command was processed, it could have * been aborted/released. We need to check this. If so, then * the command state is changed to ST_DEQUEUE and returned */ if (the_command->abort_code != CMND_OPEN) { the_command->state = ST_DEQUEUE; return 0; } if (the_command->state == ST_DONE) {# ifdef DEBUG_SCSI_THREAD printk("%s hand_to_front_end: calling xmit_response for %p id %d\n", current->comm, the_command, the_command->id);# endif if ((curr_device->template) && (curr_device->template->xmit_response)) { /* * if it is generic then we need to get the * blocksize information from the response to * the READ_CAPACITY */# ifdef GENERICIO if (the_command->cmd[0] == READ_CAPACITY) { temp = (__u8 *) ((struct scatterlist *) the_command-> req->sr_buffer)->address; if (the_command->target_id < MAX_TARGETS && the_command->lun < MAX_LUNS && !down_interruptible(&target_map_sem)) { target_map[the_command->target_id][the_command->lun] .bytes_per_block = (temp[4] << (BYTE * 3)) + (temp[5] << (BYTE * 2)) + (temp[6] << (BYTE)) + temp[7]; } up(&target_map_sem); }# endif the_command->state = ST_HANDED; if (curr_device->template->xmit_response(the_command)) { printk("%s hand_to_front_end: error in xmit_response for %p " "id %d\n", current->comm, the_command, the_command->id); return -1; } } else { printk("%s hand_to_front_end: no xmit_response function\n", current->comm); return -1; } } else if (the_command->state == ST_PENDING) {# ifdef DEBUG_SCSI_THREAD printk("%s hand_to_front_end: call to rdy_to_xfer for %p id: %d\n", current->comm, the_command, the_command->id);# endif if ((curr_device->template) && (curr_device->template->rdy_to_xfer)) { the_command->state = ST_XFERRED; if (curr_device->template->rdy_to_xfer(the_command)) { printk("%s hand_to_front_end: error in rdy_to_xfer for %p " "id %d\n", current->comm, the_command, the_command->id); return -1; } } else { printk("%s hand_to_front_end: no rdy_to_xfer function\n", current->comm); return -1; } } else { printk("%s hand_to_front_end: command %p id: %d bad state %d\n", current->comm, the_command, the_command->id, the_command->state); return -1; } return 0;}/* * abort_notify: This function is used to notify to the front end driver * that a command has been successfully aborted * INPUT: Target_Scsi_Cmnd * OUTPUT: none */static intabort_notify(Target_Scsi_Message * msg){ Target_Scsi_Cmnd *cmnd; Scsi_Target_Device *curr_device; if (msg && msg->value) cmnd = (Target_Scsi_Cmnd *) msg->value; else { printk("abort_notify: null cmnd in the msg\n"); return -1; } /* get the device template corresponding to the device_id */ for (curr_device = target_data.st_device_list; curr_device != NULL; curr_device = curr_device->next) { if (curr_device->id == cmnd->dev_id) break; } if (curr_device == NULL) { printk("abort_notify: Could not find the device\n"); return -1; } if ((curr_device->template) && (curr_device->template
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -