📄 scsi_target.c
字号:
intscsi_target_done(Target_Scsi_Cmnd * the_command){ the_command->state = ST_DEQUEUE; /* awaken scsi_target_process_thread to dequeue stuff */ if (atomic_read(&target_data.target_sem.count) <= 0) { up(&target_data.target_sem); } return 0;}/* * scsi_release: This function is called by a low-level driver when it * determines that it does not responses to certain commands. Situations * like this happen when for instance a LIP is received in a Fibre * Channel Loop or when a Logout is received in iSCSI before command * execution is completed. The low-level driver may no longer care about * receiving responses for those commands. This function can be called * from within interrupt context * INPUT: command to release * OUTPUT: 0 if success, < 0 if there is trouble */intscsi_release(Target_Scsi_Cmnd * cmnd){ cmnd->abort_code = CMND_RELEASED; /* * if a command is processing, it is not nice to * dequeue a command, as we will get a response * anyways. This may be an inherent race condn * We catch what we can and move on. A second * check performed when hand_to_front_end is * called should catch the remaining commands * - Ashish */ if (cmnd->state != ST_PROCESSING) cmnd->state = ST_DEQUEUE; /* wake up scsi_process_target_thread so it can dequeue stuff */ if (atomic_read(&target_data.target_sem.count) <= 0) { up(&target_data.target_sem); } return 0;}/* * rx_task_mgmt_fn: This function is called by a low-level driver to * indicate to the Mid-level that it has received a management function. * This function will decide the action to be taken in response to this * management function. This function will in turn create a message list * in the mid-level. CAN BE CALLED FROM INTERRUPT CONTEXT * INPUT: device, function, command - if relevant * OUTPUT: message or NULL if there is trouble * Definition of value: * 1. ABORT TASK * value = Target_Scsi_Cmnd * 2. ABORT TASK SET * This function cannot be directly performed since the Mid-Level * has no knowledge of what Initiators are logged in to the front- * end. This functionality can be achieved by issuing ABORTS to * various commands identified within the Task Set by the front * -end. value = N/A * 3. CLEAR ACA * I dont understand this one * 4. CLEAR TASK SET * Implement similar to ABORT Task Set - I know that all semantics * for this cannot be implemented (Any ideas ?) * 5. LUN RESET * set value = pointer to LUN * 6. TARGET RESET * set value = NULL */struct SM *rx_task_mgmt_fn(struct STD *dev, int fn, void *value){ unsigned long flags; Target_Scsi_Message *msg; if ((fn < TMF_ABORT_TASK) && (fn > TMF_TASK_REASSIGN)) { printk("rx_task_mgmt_fn: Invalid value %d for Task Mgmt function\n", fn); return NULL; } if ((fn == TMF_ABORT_TASK_SET) || (fn == TMF_CLEAR_ACA) || (fn == TMF_CLEAR_TASK_SET)) { printk("rx_task_mgmt_fn: task mgmt function %d not implemented\n", fn); return NULL; } if ((fn == TMF_ABORT_TASK) && (value == NULL)) { printk("rx_task_mgmt_fn: Cannot abort a NULL command\n"); return NULL; } msg = (Target_Scsi_Message *)kmalloc(sizeof(Target_Scsi_Message), GFP_KERNEL | GFP_ATOMIC); if (!msg) { printk("rx_task_mgmt_fn: no space for scsi message\n"); return NULL; } msg->next = NULL; msg->prev = NULL; msg->device = dev; msg->value = value; msg->message = fn; spin_lock_irqsave(&target_data.msg_lock, flags); if (!target_data.msgq_start) { target_data.msgq_start = target_data.msgq_end = msg; } else { target_data.msgq_end->next = msg; target_data.msgq_end = msg; } spin_unlock_irqrestore(&target_data.msg_lock, flags); /* wake up scsi_target_process_thread */ if (atomic_read(&target_data.target_sem.count) <= 0) { up(&target_data.target_sem); } return msg;}# if defined (FILEIO) || defined (GENERICIO)/* * build_filp_table: builds up a table of open file descriptors. * INPUT: nothing * OUTPUT: 0 if all ok, < 0 if there was trouble */static intbuild_filp_table(void){ char *tmp; int error; int targ, lun, max_files, max_luns; mm_segment_t old_fs; struct file *dev_file; struct target_map_item *this_item; max_files = MAX_FILE_TARGETS; if (max_files > MAX_TARGETS) max_files = MAX_TARGETS; max_luns = MAX_FILE_LUNS; if (max_luns > MAX_LUNS) max_luns = MAX_LUNS; for (targ = 0; targ < max_files; targ++) { for (lun = 0; lun < max_luns; lun++) { this_item = &target_map[targ][lun];# if defined (GENERICIO) if (targ == 0) sprintf(this_item->file_name, "/dev/sg%d", lun); else sprintf(this_item->file_name, "dev/sg%d%d", targ, lun);# endif# if defined (FILEIO) sprintf(this_item->file_name, "scsi_disk_file_%d_%d", targ, lun);# endif printk("opening device %s\n", this_item->file_name); old_fs = get_fs(); set_fs(get_ds()); tmp = getname(this_item->file_name); set_fs(old_fs); error = PTR_ERR(tmp); if (IS_ERR(tmp)) { printk("build_filp_table: getname returned error %d\n", error); return -1; } /* open a file or a scsi_generic device */# ifdef GENERICIO dev_file = filp_open(tmp, O_RDWR | O_NONBLOCK, 0600);# endif# ifdef FILEIO dev_file = filp_open(tmp, O_RDWR | O_NONBLOCK | O_CREAT, 0600);# endif putname(tmp); if (IS_ERR(dev_file)) { error = PTR_ERR(dev_file); if (targ + lun == 0) { printk("build_filp_table: filp_open returned error %d\n", error); return -1; } else goto out_of_loop; } else { /* mark this device "in-use" and save info about it */ this_item->the_file = dev_file; this_item->max_blocks = FILESIZE; this_item->bytes_per_block = BLOCKSIZE; this_item->in_use = 1; printk("opened file %s as id: %d lun: %d\n", this_item->file_name, targ, lun); target_count++; } } }out_of_loop:# ifdef GENERICIO /* also we spawn a second thread to receive signals */ init_MUTEX_LOCKED(&target_data.signal_sem); init_MUTEX_LOCKED(&target_data.sig_thr_sem); kernel_thread((int (*)(void *)) signal_process_thread, NULL, 0);# endif return 0;}/* * close_filp_table: to close all the open file descriptors * INPUT: None * OUTPUT: None */static voidclose_filp_table(void){ __u32 targ, lun; struct target_map_item *this_item; if (!down_interruptible(&target_map_sem)) { for (targ = 0; targ < MAX_TARGETS; targ++) { for (lun = 0; lun < MAX_LUNS; lun++) { this_item = &target_map[targ][lun]; if (this_item->the_file) { filp_close(this_item->the_file, NULL); this_item->the_file = NULL; this_item->in_use = 0; } } } up(&target_map_sem); }}# endif/* * : allocates scatter-gather buffers for the received command * The assumption is that all front-ends use scatter-gather and so do * the back-ends ... this may change. * INPUT: Scsi_Request for which space has to be allocated, space needed * OUTPUT: 0 if everything is okay, < 0 if there is trouble */static intget_space(Scsi_Request * req, int space /* in bytes */ ){ /* We assume that scatter gather is used universally */ struct scatterlist *st_buffer; int buff_needed, i; int count; /* we assume that all buffers are split by page size */ /* get enough scatter gather entries */ buff_needed = space / PAGE_SIZE; if (space > (buff_needed * PAGE_SIZE)) buff_needed++; /*ramesh - added check for allocating memory */ if (buff_needed == 0) buff_needed = 1; st_buffer = (struct scatterlist *)kmalloc(buff_needed * sizeof(struct scatterlist), GFP_KERNEL | GFP_ATOMIC); if (!st_buffer) { printk("get_space: no space for st_buffer\n"); return -1; } memset(st_buffer, 0, buff_needed * sizeof(struct scatterlist)); /* get necessary buffer space */ for (i = 0, count = space; i < buff_needed; i++, count -= PAGE_SIZE) {/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 st_buffer[i].page = alloc_pages(GFP_DMA | GFP_KERNEL, 0); if (!st_buffer[i].page) { printk("get_space: no space for st_buffer[%d].page\n", i); return -1; } sg_dma_address(st_buffer + i) = (dma_addr_t)kmap(st_buffer[i].page); /* this should always be 0 */ st_buffer[i].offset = (unsigned long) sg_dma_address(st_buffer + i) & ~PAGE_MASK; if (count > PAGE_SIZE) sg_dma_len(st_buffer + i) = PAGE_SIZE; else sg_dma_len(st_buffer + i) = count;#else st_buffer[i].address = (__u8 *) __get_free_pages(GFP_DMA | GFP_KERNEL, 0); if (!st_buffer[i].address) { printk("get_space: no space for st_buffer[%d].address\n", i); return -1; } if (count > PAGE_SIZE) st_buffer[i].length = PAGE_SIZE; else st_buffer[i].length = count;#endif/* df revised begin */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)/* Ming Zhang, mingz@ele.uri.edu */#ifndef K26 /* From 2.4.13, the structure scatterlist add a field "page", which is checked * in pci_map_sg(pci.h), which is also changed from 2.4.13. So should set a NULL as * initial value */ st_buffer[i].page = NULL;#endif#endif/* df revised end */# ifdef DEBUG_HANDLE_CMD/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 printk("get_space: st_buffer[%d] = %d\n", i, sg_dma_len(st_buffer + i));#else printk("get_space: st_buffer[%d] = %d\n", i, st_buffer[i].length);#endif# endif } req->sr_bufflen = space; req->sr_buffer = st_buffer; req->sr_sglist_len = buff_needed * sizeof(struct scatterlist); req->sr_use_sg = buff_needed; return 0;}#if !defined(DISKIO) || !defined(TRUST_CDB)/* * Returns size of space allocated for LUN list > 0 if all ok, * -1 on error after giving message */static intallocate_report_lun_space(Target_Scsi_Cmnd * cmnd){ int i, luns, size;# ifdef DEBUG_HANDLE_CMD printk("REPORT_LUNS received\n");# endif /* perform checks on Report LUNS - LATER */ if (cmnd->req->sr_cmnd[2] != 0) { printk("%s Select_Report in report_luns not zero\n", current->comm); } /* set data direction */ cmnd->req->sr_data_direction = SCSI_DATA_READ; /* get length */ if (cmnd->target_id >= MAX_TARGETS) { printk("%s target id %u >= MAX_TARGETS %u\n", current->comm, cmnd->target_id, MAX_TARGETS); return -1; } luns = 0; if (!down_interruptible(&target_map_sem)) { for (i = 0; i < MAX_LUNS; i++) { if (target_map[cmnd->target_id][i].in_use) luns++; } up(&target_map_sem); } if (luns == 0) { printk("%s No luns in use for target id %u\n", current->comm, cmnd->target_id); return -1; } printk("%s REPORT_LUNS: target id %u reporting %d luns\n", current->comm, cmnd->target_id, luns); /* allocate space */ size = luns * 8; if (get_space(cmnd->req, size + 8)) { printk("%s get_space returned an error for %d\n", current->comm, cmnd->id); return -1; } return size;}/* * get_allocation_length: This function looks at the received command * and calculates the size of the buffer to be allocated in order to * execute the command. * INPUT: pointer to command received * OUTPUT: buffer needing to be allocated or < 0 if there is an error */static __u32 __attribute__ ((no_instrument_function))get_allocation_length(__u8 *cmd){ __u32 err = 0; switch (cmd[0]) { case INQUIRY: case MODE_SENSE: case MODE_SELECT: { err = cmd[ALLOC_LEN_6];# ifdef DEBUG_ALLOCN_LEN printk ("get_allocation_length: INQUIRY/MODE SENSE/MODE SELECT length %d\n", err);# endif break; } case WRITE_10: case READ_10: case VERIFY: { err = (cmd[ALLOC_LEN_10] << BYTE) + cmd[ALLOC_LEN_10 + 1]; err *= BLOCKSIZE;# ifdef DEBUG_ALLOCN_LEN printk("get_allocation_length: READ_10/WRITE_10 length %d\n", err);# endif break; } /* cdeng, August 24 2002, Report luns */ case REPORT_LUNS: { /* Bjorn Thordarson, 10 May 2004 */ /***** err = (cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) + cmd[9]; *****/ err = 0;# ifdef DEBUG_ALLOCN_LEN printk("get_allocation_length: REPORT_LUNS length %d - FIXME\n", err);# endif break; }# ifdef TAPE_DEVICE case READ_6: case WRITE_6: { err = (cmd[2] << 16) + (cmd[3] << 8) + cmd[4]; if (1 == cmd[1]) { err *= BLOCKSIZE; /*ramesh - need to check the block size, right now it is fixed */ }# ifdef DEBUG_ALLOCN_LEN printk("get_allocation_length: READ_6/WRITE_6 length %d\n", err);# endif break; }#else case READ_6: case WRITE_6:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -