⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi_target.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			case TMF_TARGET_WARM_RESET:			case TMF_TARGET_COLD_RESET:				{					spin_lock_irqsave(&target_data.cmd_queue_lock, flags);					list_for_each_entry(cmd_curr,&target_data.cmd_queue,link) {						scsi_release(cmd_curr);					}					spin_unlock_irqrestore(&target_data.cmd_queue_lock, flags);					aen_notify(msg->message, 0);					break;				}			default:				{					printk("%s Bad message code %d\n", current->comm,							msg->message);					break;				}			}	/* switch */			kfree(msg);			msg = NULL;		}# ifdef DEBUG_SCSI_THREAD		printk("%s Searching command queue\n", current->comm);# endif		/* There is a harmless race here.		 * This loop is the ONLY place a command can be removed from the queue.		 * So once we get lptr, it cannot be made invalid elsewhere.		 * However, if a new element is added to the end of the queue		 * (the ONLY place new elements are ever added) as lptr is being		 * picked up or as next is being picked up or after next has been		 * picked up, then we might not see this new element on the		 * next iteration of this loop.		 * That should not cause a problem, because the ONLY place a new		 * command can be added to the queue is in rx_cmnd(), and after		 * adding the new command to the queue, rx_cmnd() also does an "up"		 * on target_sem, which will restart the outer loop of this thread		 * and we will be back into this loop again in no time.		 * Why do we say this race is harmless?		 * The loop initialization generated by list_for_each_safe:		 *		lptr = (&target_data.cmd_queue)->next		 * and the code:		 *		next = lptr->next;		 * will always work properly, because list_add_tail() always sets		 * the referenced "next" field last when adding a new element to		 * the queue (i.e., AFTER all other pointer fields are set up		 * correctly).   Therefore, there is a race with list_add_tail(),		 * but we always get a pointer to a valid structure (either the head		 * of the list, in which case we don't process the new element, or		 * the new element which is completely filled in, in which case we		 * do process the new element).		 */		list_for_each_safe(lptr, next, &target_data.cmd_queue) {# ifdef DEBUG_SCSI_THREAD			printk("%s lptr %p next %p\n", current->comm, lptr, next);# endif			cmd_curr = list_entry(lptr, Target_Scsi_Cmnd, link);# ifdef DEBUG_SCSI_THREAD			printk("%s cmd_curr %p\n", current->comm, cmd_curr);# endif# ifdef DEBUG_SCSI_THREAD			printk("%s command %p id %d status %d\n", current->comm, cmd_curr,				   cmd_curr->id, cmd_curr->state);# endif			/* is command received */			if (cmd_curr->state == ST_NEW_CMND) {# ifdef DEBUG_SCSI_THREAD				printk("%s New command %p id: %d\n", current->comm, cmd_curr,					   cmd_curr->id);# endif				lun = cmd_curr->lun;#if defined(DISKIO)				if (!down_interruptible(&target_map_sem)) {#if defined(TRUST_CDB)					list_for_each_entry(this_item, &target_map_list, link) {						if (this_item->target_id == cmd_curr->target_id							&& this_item->in_use) {							this_device = this_item->the_device;							break;						}					}#else					if (cmd_curr->target_id < MAX_TARGETS) {						if (lun < MAX_LUNS) {							this_item = &target_map[cmd_curr->target_id][lun];							if (this_item->in_use) {								this_device = this_item->the_device;							}						}						if (!this_device) {							this_item = &target_map[cmd_curr->target_id][0];							if (this_item->in_use) {								printk("%s No lun %u for target id %u, "									   "using lun 0 instead\n",									   current->comm, lun, cmd_curr->target_id);								this_device = this_item->the_device;								lun = 0;							}						}					}#endif					up(&target_map_sem);				}				if (this_device) {/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26					cmd_curr->req = scsi_allocate_request(this_device, GFP_ATOMIC);#else					cmd_curr->req = scsi_allocate_request(this_device);#endif				} else {					printk("%s No device for lun %u target id %u\n",							current->comm, lun, cmd_curr->target_id);					goto scsi_thread_out;				}#else				cmd_curr->req = (Scsi_Request *)kmalloc(sizeof(Scsi_Request),													GFP_KERNEL | GFP_ATOMIC);				if (cmd_curr->req) {					memset(cmd_curr->req, 0, sizeof(Scsi_Request));					if (lun >= MAX_LUNS)						cmd_curr->req->sr_allowed = 1;				}#endif				if (!cmd_curr->req) {					printk("%s no space for Scsi_Request\n", current->comm);					goto scsi_thread_out;				}				memcpy(cmd_curr->req->sr_cmnd, cmd_curr->cmd, cmd_curr->len);				if (handle_cmd(cmd_curr)) {					printk("%s error in handle_cmd for command %d\n",						   current->comm, cmd_curr->id);					/* is bailing out a good idea? */					goto scsi_thread_out;				}			}			/* is a command pending */			if (cmd_curr->state == ST_PENDING) {# ifdef DEBUG_SCSI_THREAD				printk("%s command %p id %d pending\n", current->comm,						cmd_curr, cmd_curr->id);# endif				/* call the rdy_to_xfer function */				if (hand_to_front_end(cmd_curr)) {					printk("%s error in hand_to_front_end for command %d\n",						   current->comm, cmd_curr->id);					goto scsi_thread_out;				}			}			/* is data received */			if (cmd_curr->state == ST_TO_PROCESS) {				/*				 * we have received the data - does this				 * go off to handle_cmd again ?				 */# ifdef DEBUG_SCSI_THREAD				printk("%s command %p id %d with data received\n",					   current->comm, cmd_curr, cmd_curr->id);# endif				if (handle_cmd(cmd_curr)) {					printk("%s error in handle_cmd for command %d\n",						   current->comm, cmd_curr->id);					/* is bailing out a good idea? */					goto scsi_thread_out;				}			}# ifdef GENERICIO			/* is command processed */			if (cmd_curr->state == ST_PROCESSED) {# ifdef DEBUG_SCSI_THREAD				printk("%s command %p id %d processed\n",						current->comm, cmd_curr, cmd_curr->id);# endif				/* we have some reading to do */				dev_file = cmd_curr->fd;				if ((dev_file) && (dev_file->f_op) && (dev_file->f_op->read)) {					old_fs = get_fs();					set_fs(get_ds());					i = dev_file->f_op->read(dev_file,											 (__u8 *) cmd_curr->sg,											 sizeof(sg_io_hdr_t),											 &dev_file->f_pos);					set_fs(old_fs);					if ((i < 0) && (i != -EAGAIN)) {						printk("%s read error %d\n", current->comm, i);						goto scsi_thread_out;					}					cmd_curr->state = ST_DONE;				}			}# endif			/* is command done */			if (cmd_curr->state == ST_DONE) {				/*				 * hand it off to the front end driver				 * to transmit				 *//* Ming Zhang, mingz@ele.uri.edu */#ifdef K26#ifdef DISKIO				/*				 * for DISKIO under K26, should reassign sg_dma_address here				 */				for (i = 0; i < cmd_curr->req->sr_use_sg; i++) {					sg_dma_address(((struct scatterlist *)cmd_curr->req->sr_buffer) + i) =						(dma_addr_t)page_address(((struct scatterlist *)cmd_curr->req->sr_buffer)[i].page);					((struct scatterlist *)cmd_curr->req->sr_buffer)[i].offset = (unsigned long)						sg_dma_address(((struct scatterlist *)cmd_curr->req->sr_buffer) + i) & ~PAGE_MASK;				}#endif#endif# ifdef DEBUG_SCSI_THREAD				printk("%s command %p id %d done\n", current->comm, cmd_curr,					   cmd_curr->id);# endif				if (hand_to_front_end(cmd_curr)) {					printk("%s error in hand_to_front_end for command %d\n",						   current->comm, cmd_curr->id);					goto scsi_thread_out;				}			}			/* can command be dequeued */			if (cmd_curr->state == ST_DEQUEUE) {				/*				 * dequeue the command and free it				 */# ifdef DEBUG_SCSI_THREAD				printk("%s command %p id %d - to dequeue req %p\n",						current->comm, cmd_curr, cmd_curr->id, cmd_curr->req);# endif# ifdef GENERICIO				/* free up the SCSI generic stuff */				if (cmd_curr->sg->dxferp)					kfree(cmd_curr->sg->dxferp);				kfree(cmd_curr->sg->sbp);				kfree(cmd_curr->sg);# endif				if (cmd_curr->req) {					/* free up pages */					st_list = (struct scatterlist *) cmd_curr->req->sr_buffer;					for (i = 0; i < cmd_curr->req->sr_use_sg; i++) {/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26						kunmap(st_list[i].page);						__free_page(st_list[i].page);#else						free_page((long int) st_list[i].address);#endif					}# ifdef DEBUG_SCSI_THREAD					printk("%s command %p id %d - freed %d pages\n",							current->comm, cmd_curr, cmd_curr->id, i);# endif					/* free up scatterlist */					if (cmd_curr->req->sr_use_sg)						kfree(st_list);					/* free up Scsi_Request */# ifdef DISKIO					scsi_release_request(cmd_curr->req);# else					kfree(cmd_curr->req);# endif				}				/* dequeue and free up Target_Scsi_Cmnd */				spin_lock_irqsave(&target_data.cmd_queue_lock, flags);				list_del(lptr);				spin_unlock_irqrestore(&target_data.cmd_queue_lock, flags);				kfree(cmd_curr);# ifdef DEBUG_SCSI_THREAD				printk("%s command %p - all free\n", current->comm, cmd_curr);# endif			}		}# ifdef DEBUG_SCSI_THREAD		printk("%s going back to sleep again\n", current->comm);# endif	}scsi_thread_out:	up(&target_data.thread_sem);	printk("%s Exiting pid %d\n", current->comm, current->pid);	return;}/* * rx_cmnd: this function is the basic function called by any front end * when it receives a SCSI command. The rx_cmnd function then fills up * a Target_Scsi_Cmnd struct, adds to the queue list, awakens the mid- * level thread and then returns the struct to the front end driver * INPUT:	device, target_id, lun, SCSI CDB as an unsigned char * 		length of the command (or size of scsi_cdb array if * 		unavailable * OUTPUT:	Target_Scsi_Cmnd struct or NULL if things go wrong */Target_Scsi_Cmnd *rx_cmnd(Scsi_Target_Device * device, __u64 target_id,	__u64 lun, __u8 *scsi_cdb, int len, int datalen, int in_flags,	Target_Scsi_Cmnd **result_command){	Target_Scsi_Cmnd *command;	unsigned long flags;	*result_command = NULL;	if (!target_data.thread_id) {		printk("rx_cmnd: No Mid-level running !!!!\n");		return NULL;	}	if (!device) {		printk("rx_cmnd: No device given !!!!\n");		return NULL;	}	*result_command = command =		(Target_Scsi_Cmnd *)kmalloc(sizeof(Target_Scsi_Cmnd),						GFP_KERNEL | GFP_ATOMIC);	if (command == NULL) {		printk("rx_cmnd: No space for command\n");		/* sendsig (SIGKILL, target_data.thread_id, 0); */		return NULL;	}# ifdef DEBUG_RX_CMND	printk("rx_cmnd: filling up command struct %p\n", command);# endif	/* fill in Target_Scsi_Cmnd */	command->req = NULL;	command->state = ST_NEW_CMND;	command->abort_code = CMND_OPEN;	command->device = device;	command->dev_id = device->id;	/*ramesh@global.com	   added data length and flgs to the command structure */	command->datalen = datalen;	command->flags = in_flags;	/* cdeng change target_id later if lun doesn't match */	command->target_id = target_id;	command->lun = unpack_lun((__u8 *)&lun);	INIT_LIST_HEAD(&command->link);	if ((len <= MAX_COMMAND_SIZE) && (len > 0))		command->len = len;	else {//          printk ("setting cmd len to %d instead of %d\n", MAX_COMMAND_SIZE, len);		command->len = MAX_COMMAND_SIZE;	}	memcpy(command->cmd, scsi_cdb, command->len);# if defined (FILEIO) || defined (GENERICIO)	/* fill in the file pointer */	command->fd = NULL;	if (command->target_id < MAX_TARGETS && command->lun < MAX_LUNS		&& !down_interruptible(&target_map_sem)) {			struct target_map_item *this_item;			this_item = &target_map[command->target_id][command->lun];			if (this_item->in_use) {				command->fd = this_item->the_file;# if defined (GENERICIO)				command->blk_size = this_item->bytes_per_block;# endif		}		up(&target_map_sem);	}	if (command->fd == NULL) {		printk("%s No target for command with targetid %u, lun %u\n",			   current->comm, command->target_id, command->lun);		/*		 * Arne Redlich <agr1@sourceforge.net>:		 * kfree()'ing the command and returning NULL here will cause		 * the connection / session to be killed, rendering the target		 * unusable with initiators that don't understand/use the		 * REPORT_LUNS response and instead rely on probing LUNs by		 * INQUIRYs to a range of (possibly not available) LUNs		 * - which is actually the case with the Cisco (3.4.3)		 * and UNH (1.5.3, 1.5.4) initiators. Instead, doing nothing		 * here and letting handle_cmd() generate a TYPE_NO_LUN INQUIRY		 * response catches this quite gracefully.		 */	}# endif	spin_lock_irqsave(&target_data.cmd_queue_lock, flags);# ifdef DEBUG_RX_CMND	printk("rx_cmnd: locked cmd_queue_lock for %p\n", command);# endif	command->id = ++target_data.command_id;	/* check this to make sure you dont have a command with this id ?????	 * IGNORE FOR NOW	 */	if (!command->id) {		/* FOR WRAP AROUNDS */		command->id = ++target_data.command_id;	}	list_add_tail(&command->link, &target_data.cmd_queue);# ifdef DEBUG_RX_CMND	printk("rx_cmnd: unlock cmd_queue_lock for %p with id %d\n",command,command->id);# endif	spin_unlock_irqrestore(&target_data.cmd_queue_lock, flags);	/* wake up scsi_target_process_thread */	if (atomic_read(&target_data.target_sem.count) <= 0) {		up(&target_data.target_sem);	}	return command;}/* * scsi_rx_data: This function is called by the lower-level driver to * tell the mid-level that data corresponding to a command has been * received. This function can be called from within an interrupt * handler (??). All this function does currently is to change the * state of a command and then wake the mid-level thread to deal with * this command. * INPUT: scsi command for which data has been received (MUST not be NULL) * OUTPUT: 0 if okay else < 0 */intscsi_rx_data(Target_Scsi_Cmnd * the_command){	the_command->state = ST_TO_PROCESS;	/* wake up the mid-level scsi_target_process_thread */	if (atomic_read(&target_data.target_sem.count) <= 0) {		up(&target_data.target_sem);	}	return 0;}/* * scsi_target_done: This is the function called by the low-level driver * to signify that it has completed the execution of a given scsi cmnd * This function needs to remove the resources that have been allocated * to the given command, dequeue the command etc. This function will be * called from within the context of an interrupt handler. So, it may * be best to leave it up to the mid-level thread to actually deal with * these functions. Right now, I am setting it up so that the status of * the command is changed and the mid-level is awakened. * INPUT: scsi command to be dequeued * OUTPUT: 0 if everything is okay * 	   < 0 if there is trouble */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -