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

📄 scsi_scan.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
				if (shpnt->this_id != order_dev) {					/*					 * We need the for so our continue, etc. work fine. We put this in					 * a variable so that we can override it during the scan if we					 * detect a device *KNOWN* to have multiple logical units.					 */					max_dev_lun = (max_scsi_luns < shpnt->max_lun ?					 max_scsi_luns : shpnt->max_lun);					sparse_lun = 0;					for (lun = 0; lun < max_dev_lun; ++lun) {						if (!scan_scsis_single(channel, order_dev, lun, &max_dev_lun,								       &sparse_lun, &SDpnt, shpnt,							     scsi_result)						    && !sparse_lun)							break;	/* break means don't probe further for luns!=0 */					}	/* for lun ends */				}	/* if this_id != id ends */			}	/* for dev ends */		}		/* for channel ends */	}			/* if/else hardcoded */      leave:	{			/* Unchain SRpnt from host_queue */		Scsi_Device *prev, *next;		Scsi_Device *dqptr;		for (dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next)			continue;		if (dqptr) {			prev = dqptr->prev;			next = dqptr->next;			if (prev)				prev->next = next;			else				shpnt->host_queue = next;			if (next)				next->prev = prev;		}	}	/* Last device block does not exist.  Free memory. */	if (SDpnt != NULL) {		blk_cleanup_queue(&SDpnt->request_queue);		kfree((char *) SDpnt);	}	/* If we allocated a buffer so we could do DMA, free it now */	if (scsi_result != &scsi_result0[0] && scsi_result != NULL) {		kfree(scsi_result);	} {		Scsi_Device *sdev;		Scsi_Cmnd *scmd;		SCSI_LOG_SCAN_BUS(4, printk("Host status for host %p:\n", shpnt));		for (sdev = shpnt->host_queue; sdev; sdev = sdev->next) {			SCSI_LOG_SCAN_BUS(4, printk("Device %d %p: ", sdev->id, sdev));			for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {				SCSI_LOG_SCAN_BUS(4, printk("%p ", scmd));			}			SCSI_LOG_SCAN_BUS(4, printk("\n"));		}	}}/* * The worker for scan_scsis. * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on. * Global variables used : scsi_devices(linked list) */static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,	       int *sparse_lun, Scsi_Device ** SDpnt2, 		      struct Scsi_Host *shpnt, char *scsi_result){	char devname[64];	unsigned char scsi_cmd[MAX_COMMAND_SIZE];	struct Scsi_Device_Template *sdtpnt;	Scsi_Device *SDtail, *SDpnt = *SDpnt2;	Scsi_Request * SRpnt;	int bflags, type = -1;	extern devfs_handle_t scsi_devfs_handle;	SDpnt->host = shpnt;	SDpnt->id = dev;	SDpnt->lun = lun;	SDpnt->channel = channel;	SDpnt->online = TRUE;	scsi_build_commandblocks(SDpnt); 	/* Some low level driver could use device->type (DB) */	SDpnt->type = -1;	/*	 * Assume that the device will have handshaking problems, and then fix this	 * field later if it turns out it doesn't	 */	SDpnt->borken = 1;	SDpnt->was_reset = 0;	SDpnt->expecting_cc_ua = 0;	SDpnt->starved = 0;	SRpnt = scsi_allocate_request(SDpnt);	/*	 * We used to do a TEST_UNIT_READY before the INQUIRY but that was 	 * not really necessary.  Spec recommends using INQUIRY to scan for	 * devices (and TEST_UNIT_READY to poll for media change). - Paul G.	 */	SCSI_LOG_SCAN_BUS(3, printk("scsi: performing INQUIRY\n"));	/*	 * Build an INQUIRY command block.	 */	scsi_cmd[0] = INQUIRY;	scsi_cmd[1] = (lun << 5) & 0xe0;	scsi_cmd[2] = 0;	scsi_cmd[3] = 0;	scsi_cmd[4] = 255;	scsi_cmd[5] = 0;	SRpnt->sr_cmd_len = 0;	SRpnt->sr_data_direction = SCSI_DATA_READ;	scsi_wait_req (SRpnt, (void *) scsi_cmd,	          (void *) scsi_result,	          256, SCSI_TIMEOUT+4*HZ, 3);	SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n",		SRpnt->sr_result ? "failed" : "successful", SRpnt->sr_result));	if (SRpnt->sr_result) {		scsi_release_request(SRpnt);		return 0;	/* assume no peripheral if any sort of error */	}	/*	 * Check the peripheral qualifier field - this tells us whether LUNS	 * are supported here or not.	 */	if ((scsi_result[0] >> 5) == 3) {		scsi_release_request(SRpnt);		return 0;	/* assume no peripheral if any sort of error */	}	/*	 * Get any flags for this device.  	 */	bflags = get_device_flags (scsi_result);	 /*   The Toshiba ROM was "gender-changed" here as an inline hack.	      This is now much more generic.	      This is a mess: What we really want is to leave the scsi_result	      alone, and just change the SDpnt structure. And the SDpnt is what	      we want print_inquiry to print.  -- REW	 */	if (bflags & BLIST_ISDISK) {		scsi_result[0] = TYPE_DISK;                                                		scsi_result[1] |= 0x80;     /* removable */	}	if (bflags & BLIST_ISROM) {		scsi_result[0] = TYPE_ROM;		scsi_result[1] |= 0x80;     /* removable */	}    	memcpy(SDpnt->vendor, scsi_result + 8, 8);	memcpy(SDpnt->model, scsi_result + 16, 16);	memcpy(SDpnt->rev, scsi_result + 32, 4);	SDpnt->removable = (0x80 & scsi_result[1]) >> 7;	/* Use the peripheral qualifier field to determine online/offline */	if (((scsi_result[0] >> 5) & 7) == 1) 	SDpnt->online = FALSE;	else SDpnt->online = TRUE;	SDpnt->lockable = SDpnt->removable;	SDpnt->changed = 0;	SDpnt->access_count = 0;	SDpnt->busy = 0;	SDpnt->has_cmdblocks = 0;	/*	 * Currently, all sequential devices are assumed to be tapes, all random	 * devices disk, with the appropriate read only flags set for ROM / WORM	 * treated as RO.	 */	switch (type = (scsi_result[0] & 0x1f)) {	case TYPE_TAPE:	case TYPE_DISK:	case TYPE_MOD:	case TYPE_PROCESSOR:	case TYPE_SCANNER:	case TYPE_MEDIUM_CHANGER:	case TYPE_ENCLOSURE:	case TYPE_COMM:		SDpnt->writeable = 1;		break;	case TYPE_WORM:	case TYPE_ROM:		SDpnt->writeable = 0;		break;	default:		printk("scsi: unknown type %d\n", type);	}	SDpnt->device_blocked = FALSE;	SDpnt->device_busy = 0;	SDpnt->single_lun = 0;	SDpnt->soft_reset =	    (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);	SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;	SDpnt->type = (type & 0x1f);	print_inquiry(scsi_result);        sprintf (devname, "host%d/bus%d/target%d/lun%d",                 SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);        if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname);        else SDpnt->de = devfs_mk_dir (scsi_devfs_handle, devname, NULL);	for (sdtpnt = scsi_devicelist; sdtpnt;	     sdtpnt = sdtpnt->next)		if (sdtpnt->detect)			SDpnt->attached +=			    (*sdtpnt->detect) (SDpnt);	SDpnt->scsi_level = scsi_result[2] & 0x07;	if (SDpnt->scsi_level >= 2 ||	    (SDpnt->scsi_level == 1 &&	     (scsi_result[3] & 0x0f) == 1))		SDpnt->scsi_level++;	/*	 * Accommodate drivers that want to sleep when they should be in a polling	 * loop.	 */	SDpnt->disconnect = 0;	/*	 * Set the tagged_queue flag for SCSI-II devices that purport to support	 * tagged queuing in the INQUIRY data.	 */	SDpnt->tagged_queue = 0;	if ((SDpnt->scsi_level >= SCSI_2) &&	    (scsi_result[7] & 2) &&	    !(bflags & BLIST_NOTQ)) {		SDpnt->tagged_supported = 1;		SDpnt->current_tag = 0;	}	/*	 * Some revisions of the Texel CD ROM drives have handshaking problems when	 * used with the Seagate controllers.  Before we know what type of device	 * we're talking to, we assume it's borken and then change it here if it	 * turns out that it isn't a TEXEL drive.	 */	if ((bflags & BLIST_BORKEN) == 0)		SDpnt->borken = 0;	/*	 * If we want to only allow I/O to one of the luns attached to this device	 * at a time, then we set this flag.	 */	if (bflags & BLIST_SINGLELUN)		SDpnt->single_lun = 1;	/*	 * These devices need this "key" to unlock the devices so we can use it	 */	if ((bflags & BLIST_KEY) != 0) {		printk("Unlocked floptical drive.\n");		SDpnt->lockable = 0;		scsi_cmd[0] = MODE_SENSE;		scsi_cmd[1] = (lun << 5) & 0xe0;		scsi_cmd[2] = 0x2e;		scsi_cmd[3] = 0;		scsi_cmd[4] = 0x2a;		scsi_cmd[5] = 0;		SRpnt->sr_cmd_len = 0;		SRpnt->sr_data_direction = SCSI_DATA_READ;		scsi_wait_req (SRpnt, (void *) scsi_cmd,	        	(void *) scsi_result, 0x2a,	        	SCSI_TIMEOUT, 3);	}	scsi_release_request(SRpnt);	SRpnt = NULL;	scsi_release_commandblocks(SDpnt);	/*	 * This device was already hooked up to the host in question,	 * so at this point we just let go of it and it should be fine.  We do need to	 * allocate a new one and attach it to the host so that we can further scan the bus.	 */	SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device), GFP_ATOMIC);	if (!SDpnt) {		printk("scsi: scan_scsis_single: Cannot malloc\n");		return 0;	}        memset(SDpnt, 0, sizeof(Scsi_Device));	*SDpnt2 = SDpnt;	SDpnt->queue_depth = 1;	SDpnt->host = shpnt;	SDpnt->online = TRUE;	/*	 * Register the queue for the device.  All I/O requests will come	 * in through here.  We also need to register a pointer to	 * ourselves, since the queue handler won't know what device	 * the queue actually represents.   We could look it up, but it	 * is pointless work.	 */	scsi_initialize_queue(SDpnt, shpnt);	SDpnt->host = shpnt;	initialize_merge_fn(SDpnt);	/*	 * Mark this device as online, or otherwise we won't be able to do much with it.	 */	SDpnt->online = TRUE;        /*         * Initialize the object that we will use to wait for command blocks.         */	init_waitqueue_head(&SDpnt->scpnt_wait);	/*	 * Since we just found one device, there had damn well better be one in the list	 * already.	 */	if (shpnt->host_queue == NULL)		panic("scan_scsis_single: Host queue == NULL\n");	SDtail = shpnt->host_queue;	while (SDtail->next) {		SDtail = SDtail->next;	}	/* Add this device to the linked list at the end */	SDtail->next = SDpnt;	SDpnt->prev = SDtail;	SDpnt->next = NULL;	/*	 * Some scsi devices cannot be polled for lun != 0 due to firmware bugs	 */	if (bflags & BLIST_NOLUN)		return 0;	/* break; */	/*	 * If this device is known to support sparse multiple units, override the	 * other settings, and scan all of them.	 */	if (bflags & BLIST_SPARSELUN) {		*max_dev_lun = 8;		*sparse_lun = 1;		return 1;	}	/*	 * If this device is known to support multiple units, override the other	 * settings, and scan all of them.	 */	if (bflags & BLIST_FORCELUN) {		*max_dev_lun = 8;		return 1;	}	/*	 * REGAL CDC-4X: avoid hang after LUN 4	 */	if (bflags & BLIST_MAX5LUN) {		*max_dev_lun = 5;		return 1;	}	/*	 * We assume the device can't handle lun!=0 if: - it reports scsi-0	 * (ANSI SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it	 * reports scsi-1 (ANSI SCSI Revision 1) and Response Data Format 0	 */	if (((scsi_result[2] & 0x07) == 0)	    ||	    ((scsi_result[2] & 0x07) == 1 &&	     (scsi_result[3] & 0x0f) == 0))		return 0;	return 1;}

⌨️ 快捷键说明

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