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

📄 scsi.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
}/* * Function:    scsi_finish_command * * Purpose:     Pass command off to upper layer for finishing of I/O *              request, waking processes that are waiting on results, *              etc. */void scsi_finish_command(Scsi_Cmnd * SCpnt){	struct Scsi_Host *host;	Scsi_Device *device;	Scsi_Request * SRpnt;	unsigned long flags;	ASSERT_LOCK(&io_request_lock, 0);	host = SCpnt->host;	device = SCpnt->device;        /*         * We need to protect the decrement, as otherwise a race condition         * would exist.  Fiddling with SCpnt isn't a problem as the         * design only allows a single SCpnt to be active in only         * one execution context, but the device and host structures are         * shared.         */	spin_lock_irqsave(&io_request_lock, flags);	host->host_busy--;	/* Indicate that we are free */	device->device_busy--;	/* Decrement device usage counter. */	spin_unlock_irqrestore(&io_request_lock, flags);        /*         * Clear the flags which say that the device/host is no longer         * capable of accepting new commands.  These are set in scsi_queue.c         * for both the queue full condition on a device, and for a         * host full condition on the host.         */        host->host_blocked = FALSE;        device->device_blocked = FALSE;	/*	 * If we have valid sense information, then some kind of recovery	 * must have taken place.  Make a note of this.	 */	if (scsi_sense_valid(SCpnt)) {		SCpnt->result |= (DRIVER_SENSE << 24);	}	SCSI_LOG_MLCOMPLETE(3, printk("Notifying upper driver of completion for device %d %x\n",				      SCpnt->device->id, SCpnt->result));	SCpnt->owner = SCSI_OWNER_HIGHLEVEL;	SCpnt->state = SCSI_STATE_FINISHED;	/* We can get here with use_sg=0, causing a panic in the upper level (DB) */	SCpnt->use_sg = SCpnt->old_use_sg;       /*	* If there is an associated request structure, copy the data over before we call the	* completion function.	*/	SRpnt = SCpnt->sc_request;	if( SRpnt != NULL ) {	       SRpnt->sr_result = SRpnt->sr_command->result;	       if( SRpnt->sr_result != 0 ) {		       memcpy(SRpnt->sr_sense_buffer,			      SRpnt->sr_command->sense_buffer,			      sizeof(SRpnt->sr_sense_buffer));	       }	}	SCpnt->done(SCpnt);}static int scsi_register_host(Scsi_Host_Template *);static void scsi_unregister_host(Scsi_Host_Template *);/* * Function:    scsi_release_commandblocks() * * Purpose:     Release command blocks associated with a device. * * Arguments:   SDpnt   - device * * Returns:     Nothing * * Lock status: No locking assumed or required. * * Notes: */void scsi_release_commandblocks(Scsi_Device * SDpnt){	Scsi_Cmnd *SCpnt, *SCnext;	unsigned long flags; 	spin_lock_irqsave(&device_request_lock, flags);	for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) {		SDpnt->device_queue = SCnext = SCpnt->next;		kfree((char *) SCpnt);	}	SDpnt->has_cmdblocks = 0;	SDpnt->queue_depth = 0;	spin_unlock_irqrestore(&device_request_lock, flags);}/* * Function:    scsi_build_commandblocks() * * Purpose:     Allocate command blocks associated with a device. * * Arguments:   SDpnt   - device * * Returns:     Nothing * * Lock status: No locking assumed or required. * * Notes: */void scsi_build_commandblocks(Scsi_Device * SDpnt){	unsigned long flags;	struct Scsi_Host *host = SDpnt->host;	int j;	Scsi_Cmnd *SCpnt;	spin_lock_irqsave(&device_request_lock, flags);	if (SDpnt->queue_depth == 0)	{		SDpnt->queue_depth = host->cmd_per_lun;		if (SDpnt->queue_depth == 0)			SDpnt->queue_depth = 1; /* live to fight another day */	}	SDpnt->device_queue = NULL;	for (j = 0; j < SDpnt->queue_depth; j++) {		SCpnt = (Scsi_Cmnd *)		    kmalloc(sizeof(Scsi_Cmnd),				     GFP_ATOMIC |				(host->unchecked_isa_dma ? GFP_DMA : 0));		if (NULL == SCpnt)			break;	/* If not, the next line will oops ... */		memset(SCpnt, 0, sizeof(Scsi_Cmnd));		SCpnt->host = host;		SCpnt->device = SDpnt;		SCpnt->target = SDpnt->id;		SCpnt->lun = SDpnt->lun;		SCpnt->channel = SDpnt->channel;		SCpnt->request.rq_status = RQ_INACTIVE;		SCpnt->use_sg = 0;		SCpnt->old_use_sg = 0;		SCpnt->old_cmd_len = 0;		SCpnt->underflow = 0;		SCpnt->old_underflow = 0;		SCpnt->transfersize = 0;		SCpnt->resid = 0;		SCpnt->serial_number = 0;		SCpnt->serial_number_at_timeout = 0;		SCpnt->host_scribble = NULL;		SCpnt->next = SDpnt->device_queue;		SDpnt->device_queue = SCpnt;		SCpnt->state = SCSI_STATE_UNUSED;		SCpnt->owner = SCSI_OWNER_NOBODY;	}	if (j < SDpnt->queue_depth) {	/* low on space (D.Gilbert 990424) */		printk(KERN_WARNING "scsi_build_commandblocks: want=%d, space for=%d blocks\n",		       SDpnt->queue_depth, j);		SDpnt->queue_depth = j;		SDpnt->has_cmdblocks = (0 != j);	} else {		SDpnt->has_cmdblocks = 1;	}	spin_unlock_irqrestore(&device_request_lock, flags);}static int proc_scsi_gen_write(struct file * file, const char * buf,                              unsigned long length, void *data);void __init scsi_host_no_insert(char *str, int n){    Scsi_Host_Name *shn, *shn2;    int len;        len = strlen(str);    if (len && (shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC))) {	if ((shn->name = kmalloc(len+1, GFP_ATOMIC))) {	    strncpy(shn->name, str, len);	    shn->name[len] = 0;	    shn->host_no = n;	    shn->host_registered = 0;	    shn->loaded_as_module = 1; /* numbers shouldn't be freed in any case */	    shn->next = NULL;	    if (scsi_host_no_list) {		for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)		    ;		shn2->next = shn;	    }	    else		scsi_host_no_list = shn;	    max_scsi_hosts = n+1;	}	else	    kfree((char *) shn);    }}#ifdef CONFIG_PROC_FSstatic int scsi_proc_info(char *buffer, char **start, off_t offset, int length){	Scsi_Device *scd;	struct Scsi_Host *HBA_ptr;	int size, len = 0;	off_t begin = 0;	off_t pos = 0;	/*	 * First, see if there are any attached devices or not.	 */	for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {		if (HBA_ptr->host_queue != NULL) {			break;		}	}	size = sprintf(buffer + len, "Attached devices: %s\n", (HBA_ptr) ? "" : "none");	len += size;	pos = begin + len;	for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {#if 0		size += sprintf(buffer + len, "scsi%2d: %s\n", (int) HBA_ptr->host_no,				HBA_ptr->hostt->procname);		len += size;		pos = begin + len;#endif		for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {			proc_print_scsidevice(scd, buffer, &size, len);			len += size;			pos = begin + len;			if (pos < offset) {				len = 0;				begin = pos;			}			if (pos > offset + length)				goto stop_output;		}	}stop_output:	*start = buffer + (offset - begin);	/* Start of wanted data */	len -= (offset - begin);	/* Start slop */	if (len > length)		len = length;	/* Ending slop */	return (len);}static int proc_scsi_gen_write(struct file * file, const char * buf,                              unsigned long length, void *data){	struct Scsi_Device_Template *SDTpnt;	Scsi_Device *scd;	struct Scsi_Host *HBA_ptr;	char *p;	int host, channel, id, lun;	char * buffer;	int err;	if (!buf || length>PAGE_SIZE)		return -EINVAL;	if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))		return -ENOMEM;	copy_from_user(buffer, buf, length);	err = -EINVAL;	if (length < 11 || strncmp("scsi", buffer, 4))		goto out;	/*	 * Usage: echo "scsi dump #N" > /proc/scsi/scsi	 * to dump status of all scsi commands.  The number is used to specify the level	 * of detail in the dump.	 */	if (!strncmp("dump", buffer + 5, 4)) {		unsigned int level;		p = buffer + 10;		if (*p == '\0')			goto out;		level = simple_strtoul(p, NULL, 0);		scsi_dump_status(level);	}	/*	 * Usage: echo "scsi log token #N" > /proc/scsi/scsi	 * where token is one of [error,scan,mlqueue,mlcomplete,llqueue,	 * llcomplete,hlqueue,hlcomplete]	 */#ifdef CONFIG_SCSI_LOGGING		/* { */	if (!strncmp("log", buffer + 5, 3)) {		char *token;		unsigned int level;		p = buffer + 9;		token = p;		while (*p != ' ' && *p != '\t' && *p != '\0') {			p++;		}		if (*p == '\0') {			if (strncmp(token, "all", 3) == 0) {				/*				 * Turn on absolutely everything.				 */				scsi_logging_level = ~0;			} else if (strncmp(token, "none", 4) == 0) {				/*				 * Turn off absolutely everything.				 */				scsi_logging_level = 0;			} else {				goto out;			}		} else {			*p++ = '\0';			level = simple_strtoul(p, NULL, 0);			/*			 * Now figure out what to do with it.			 */			if (strcmp(token, "error") == 0) {				SCSI_SET_ERROR_RECOVERY_LOGGING(level);			} else if (strcmp(token, "timeout") == 0) {				SCSI_SET_TIMEOUT_LOGGING(level);			} else if (strcmp(token, "scan") == 0) {				SCSI_SET_SCAN_BUS_LOGGING(level);			} else if (strcmp(token, "mlqueue") == 0) {				SCSI_SET_MLQUEUE_LOGGING(level);			} else if (strcmp(token, "mlcomplete") == 0) {				SCSI_SET_MLCOMPLETE_LOGGING(level);			} else if (strcmp(token, "llqueue") == 0) {				SCSI_SET_LLQUEUE_LOGGING(level);			} else if (strcmp(token, "llcomplete") == 0) {				SCSI_SET_LLCOMPLETE_LOGGING(level);			} else if (strcmp(token, "hlqueue") == 0) {				SCSI_SET_HLQUEUE_LOGGING(level);			} else if (strcmp(token, "hlcomplete") == 0) {				SCSI_SET_HLCOMPLETE_LOGGING(level);			} else if (strcmp(token, "ioctl") == 0) {				SCSI_SET_IOCTL_LOGGING(level);			} else {				goto out;			}		}		printk(KERN_INFO "scsi logging level set to 0x%8.8x\n", scsi_logging_level);	}#endif	/* CONFIG_SCSI_LOGGING */ /* } */	/*	 * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi	 * with  "0 1 2 3" replaced by your "Host Channel Id Lun".	 * Consider this feature BETA.	 *     CAUTION: This is not for hotplugging your peripherals. As	 *     SCSI was not designed for this you could damage your	 *     hardware !	 * However perhaps it is legal to switch on an	 * already connected device. It is perhaps not	 * guaranteed this device doesn't corrupt an ongoing data transfer.	 */	if (!strncmp("add-single-device", buffer + 5, 17)) {		p = buffer + 23;		host = simple_strtoul(p, &p, 0);		channel = simple_strtoul(p + 1, &p, 0);		id = simple_strtoul(p + 1, &p, 0);		lun = simple_strtoul(p + 1, &p, 0);		printk(KERN_INFO "scsi singledevice %d %d %d %d\n", host, channel,		       id, lun);		for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {			if (HBA_ptr->host_no == host) {				break;			}		}		err = -ENXIO;		if (!HBA_ptr)			goto out;		for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {			if ((scd->channel == channel			     && scd->id == id			     && scd->lun == lun)) {				break;			}		}		err = -ENOSYS;		if (scd)			goto out;	/* We do not yet support unplugging */		scan_scsis(HBA_ptr, 1, channel, id, lun);		/* FIXME (DB) This assumes that the queue_depth routines can be used		   in this context as well, while they were all designed to be		   called only once after the detect routine. (DB) */		/* queue_depth routine moved to inside scan_scsis(,1,,,) so		   it is called before build_commandblocks() */		err = length;		goto out;	}	/*	 * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi	 * with  "0 1 2 3" replaced by your "Host Channel Id Lun".	 *	 * Consider this feature pre-BETA.	 *	 *     CAUTION: This is not for hotplugging your peripherals. As	 *     SCSI was not designed for this you could damage your	 *     hardware and thoroughly confuse the SCSI subsystem.	 *	 */	else if (!strncmp("remove-single-device", buffer + 5, 20)) {		p = buffer + 26;		host = simple_strtoul(p, &p, 0);		channel = simple_strtoul(p + 1, &p, 0);		id = simple_strtoul(p + 1, &p, 0);		lun = simple_strtoul(p + 1, &p, 0);

⌨️ 快捷键说明

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