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

📄 cciss_scsi.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
static voidcciss_update_non_disk_devices(int cntl_num, int hostno){	/* the idea here is we could get notified from /proc	   that some devices have changed, so we do a report 	   physical luns cmd, and adjust our list of devices 	   accordingly.  (We can't rely on the scsi-mid layer just	   doing inquiries, because the "busses" that the scsi 	   mid-layer probes are totally fabricated by this driver,	   so new devices wouldn't show up.	   the scsi3addr's of devices won't change so long as the 	   adapter is not reset.  That means we can rescan and 	   tell which devices we already know about, vs. new 	   devices, vs.  disappearing devices.	   Also, if you yank out a tape drive, then put in a disk	   in it's place, (say, a configured volume from another 	   array controller for instance)  _don't_ poke this driver            (so it thinks it's still a tape, but _do_ poke the scsi            mid layer, so it does an inquiry... the scsi mid layer            will see the physical disk.  This would be bad.  Need to	   think about how to prevent that.  One idea would be to 	   snoop all scsi responses and if an inquiry repsonse comes	   back that reports a disk, chuck it an return selection	   timeout instead and adjust our table...  Not sure i like	   that though.  	 */#define OBDR_TAPE_INQ_SIZE 49#define OBDR_TAPE_SIG "$DR-10"	ReportLunData_struct *ld_buff;	unsigned char *inq_buff;	unsigned char scsi3addr[8];	ctlr_info_t *c;	__u32 num_luns=0;	unsigned char *ch;	/* unsigned char found[CCISS_MAX_SCSI_DEVS_PER_HBA]; */	struct cciss_scsi_dev_t currentsd[CCISS_MAX_SCSI_DEVS_PER_HBA];	int ncurrent=0;	int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8;	int i;	c = (ctlr_info_t *) hba[cntl_num];		ld_buff = kmalloc(reportlunsize, GFP_KERNEL);	if (ld_buff == NULL) {		printk(KERN_ERR "cciss: out of memory\n");		return;	}	memset(ld_buff, 0, reportlunsize);	inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);        if (inq_buff == NULL) {                printk(KERN_ERR "cciss: out of memory\n");                kfree(ld_buff);                return;	}	if (cciss_scsi_do_report_phys_luns(c, ld_buff, reportlunsize) == 0) {		ch = &ld_buff->LUNListLength[0];		num_luns = ((ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | ch[3]) / 8;		if (num_luns > CISS_MAX_PHYS_LUN) {			printk(KERN_WARNING 				"cciss: Maximum physical LUNs (%d) exceeded.  "				"%d LUNs ignored.\n", CISS_MAX_PHYS_LUN, 				num_luns - CISS_MAX_PHYS_LUN);			num_luns = CISS_MAX_PHYS_LUN;		}	}	else {		printk(KERN_ERR  "cciss: Report physical LUNs failed.\n");		goto out;	}	/* adjust our table of devices */		for(i=0; i<num_luns; i++)	{		int devtype;		/* for each physical lun, do an inquiry */		if (ld_buff->LUN[i][3] & 0xC0) continue;		memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE);		memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8);		if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, inq_buff,			(unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {			/* Inquiry failed (msg printed already) */			devtype = 0; /* so we will skip this device. */		} else /* what kind of device is this? */			devtype = (inq_buff[0] & 0x1f);		switch (devtype)		{		  case 0x05: /* CD-ROM */ {			/* We don't *really* support actual CD-ROM devices,			 * just this "One Button Disaster Recovery" tape drive			 * which temporarily pretends to be a CD-ROM drive.			 * So we check that the device is really an OBDR tape			 * device by checking for "$DR-10" in bytes 43-48 of			 * the inquiry data.			 */				char obdr_sig[7];				strncpy(obdr_sig, &inq_buff[43], 6);				obdr_sig[6] = '\0';				if (strncmp(obdr_sig, OBDR_TAPE_SIG, 6) != 0)					/* Not OBDR device, ignore it. */					break;			}			/* fall through . . . */		  case 0x01: /* sequential access, (tape) */		  case 0x08: /* medium changer */			if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {				printk(KERN_INFO "cciss%d: %s ignored, "					"too many devices.\n", cntl_num,					DEVICETYPE(devtype));				break;			}			memcpy(&currentsd[ncurrent].scsi3addr[0], 				&scsi3addr[0], 8);			currentsd[ncurrent].devtype = devtype;			currentsd[ncurrent].bus = -1;			currentsd[ncurrent].target = -1;			currentsd[ncurrent].lun = -1;			ncurrent++;			break;		  default: 			break;		}	}	adjust_cciss_scsi_table(cntl_num, hostno, currentsd, ncurrent);out:	kfree(inq_buff);	kfree(ld_buff);	return;}static intis_keyword(char *ptr, int len, char *verb)  // Thanks to ncr53c8xx.c{	int verb_len = strlen(verb);	if (len >= verb_len && !memcmp(verb,ptr,verb_len))		return verb_len;	else		return 0;}static intcciss_scsi_user_command(int ctlr, int hostno, char *buffer, int length){	int arg_len;	if ((arg_len = is_keyword(buffer, length, "rescan")) != 0)		cciss_update_non_disk_devices(ctlr, hostno);	else		return -EINVAL;	return length;}static intcciss_scsi_proc_info(struct Scsi_Host *sh,		char *buffer, /* data buffer */		char **start, 	   /* where data in buffer starts */		off_t offset,	   /* offset from start of imaginary file */		int length, 	   /* length of data in buffer */		int func)	   /* 0 == read, 1 == write */{	int buflen, datalen;	ctlr_info_t *ci;	int i;	int cntl_num;	ci = (ctlr_info_t *) sh->hostdata[0];	if (ci == NULL)  /* This really shouldn't ever happen. */		return -EINVAL;	cntl_num = ci->ctlr;	/* Get our index into the hba[] array */	if (func == 0) {	/* User is reading from /proc/scsi/ciss*?/?*  */		buflen = sprintf(buffer, "cciss%d: SCSI host: %d\n",				cntl_num, sh->host_no);		/* this information is needed by apps to know which cciss		   device corresponds to which scsi host number without		   having to open a scsi target device node.  The device		   information is not a duplicate of /proc/scsi/scsi because		   the two may be out of sync due to scsi hotplug, rather		   this info is for an app to be able to use to know how to		   get them back in sync. */		for (i=0;i<ccissscsi[cntl_num].ndevices;i++) {			struct cciss_scsi_dev_t *sd = &ccissscsi[cntl_num].dev[i];			buflen += sprintf(&buffer[buflen], "c%db%dt%dl%d %02d "				"0x%02x%02x%02x%02x%02x%02x%02x%02x\n",				sh->host_no, sd->bus, sd->target, sd->lun,				sd->devtype,				sd->scsi3addr[0], sd->scsi3addr[1],				sd->scsi3addr[2], sd->scsi3addr[3],				sd->scsi3addr[4], sd->scsi3addr[5],				sd->scsi3addr[6], sd->scsi3addr[7]);		}		datalen = buflen - offset;		if (datalen < 0) { 	/* they're reading past EOF. */			datalen = 0;			*start = buffer+buflen;			} else			*start = buffer + offset;		return(datalen);	} else 	/* User is writing to /proc/scsi/cciss*?/?*  ... */		return cciss_scsi_user_command(cntl_num, sh->host_no,			buffer, length);	} /* cciss_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci    dma mapping  and fills in the scatter gather entries of the    cciss command, cp. */static voidcciss_scatter_gather(struct pci_dev *pdev, 		CommandList_struct *cp,			struct scsi_cmnd *cmd){	unsigned int use_sg, nsegs=0, len;	struct scatterlist *scatter = (struct scatterlist *) cmd->buffer;	__u64 addr64;	/* is it just one virtual address? */		if (!cmd->use_sg) {		if (cmd->request_bufflen) {	/* anything to xfer? */			addr64 = (__u64) pci_map_single(pdev, 				cmd->request_buffer, 				cmd->request_bufflen, 				cmd->sc_data_direction); 				cp->SG[0].Addr.lower = 			  (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);			cp->SG[0].Addr.upper =			  (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);			cp->SG[0].Len = cmd->request_bufflen;			nsegs=1;		}	} /* else, must be a list of virtual addresses.... */	else if (cmd->use_sg <= MAXSGENTRIES) {	/* not too many addrs? */		use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, 			cmd->sc_data_direction);		for (nsegs=0; nsegs < use_sg; nsegs++) {			addr64 = (__u64) sg_dma_address(&scatter[nsegs]);			len  = sg_dma_len(&scatter[nsegs]);			cp->SG[nsegs].Addr.lower =			  (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);			cp->SG[nsegs].Addr.upper =			  (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);			cp->SG[nsegs].Len = len;			cp->SG[nsegs].Ext = 0;  // we are not chaining		}	} else BUG();	cp->Header.SGList = (__u8) nsegs;   /* no. SGs contig in this cmd */	cp->Header.SGTotal = (__u16) nsegs; /* total sgs in this cmd list */	return;}static intcciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)){	ctlr_info_t **c;	int ctlr, rc;	unsigned char scsi3addr[8];	CommandList_struct *cp;	unsigned long flags;	// Get the ptr to our adapter structure (hba[i]) out of cmd->host.	// We violate cmd->host privacy here.  (Is there another way?)	c = (ctlr_info_t **) &cmd->device->host->hostdata[0];		ctlr = (*c)->ctlr;	rc = lookup_scsi3addr(ctlr, cmd->device->channel, cmd->device->id, 			cmd->device->lun, scsi3addr);	if (rc != 0) {		/* the scsi nexus does not match any that we presented... */		/* pretend to mid layer that we got selection timeout */		cmd->result = DID_NO_CONNECT << 16;		done(cmd);		/* we might want to think about registering controller itself		   as a processor device on the bus so sg binds to it. */		return 0;	}	/* printk("cciss_queue_command, p=%p, cmd=0x%02x, c%db%dt%dl%d\n", 		cmd, cmd->cmnd[0], ctlr, cmd->channel, cmd->target, cmd->lun);*/	// printk("q:%p:c%db%dt%dl%d ", cmd, ctlr, cmd->channel, 	//	cmd->target, cmd->lun);	/* Ok, we have a reasonable scsi nexus, so send the cmd down, and           see what the device thinks of it. */	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);	cp = scsi_cmd_alloc(*c);	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);	if (cp == NULL) {			/* trouble... */		printk("scsi_cmd_alloc returned NULL!\n");		/* FIXME: next 3 lines are -> BAD! <- */		cmd->result = DID_NO_CONNECT << 16;		done(cmd);		return 0;	}	// Fill in the command list header	cmd->scsi_done = done;    // save this for use by completion code 	// save cp in case we have to abort it 	cmd->host_scribble = (unsigned char *) cp; 	cp->cmd_type = CMD_SCSI;	cp->scsi_cmd = cmd;	cp->Header.ReplyQueue = 0;  // unused in simple mode	memcpy(&cp->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);	cp->Header.Tag.lower = cp->busaddr;  // Use k. address of cmd as tag		// Fill in the request block...	cp->Request.Timeout = 0;	memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));	if (cmd->cmd_len > sizeof(cp->Request.CDB)) BUG();	cp->Request.CDBLen = cmd->cmd_len;	memcpy(cp->Request.CDB, cmd->cmnd, cmd->cmd_len);	cp->Request.Type.Type = TYPE_CMD;	cp->Request.Type.Attribute = ATTR_SIMPLE;	switch(cmd->sc_data_direction)	{	  case DMA_TO_DEVICE: cp->Request.Type.Direction = XFER_WRITE; break;	  case DMA_FROM_DEVICE: cp->Request.Type.Direction = XFER_READ; break;	  case DMA_NONE: cp->Request.Type.Direction = XFER_NONE; break;	  case DMA_BIDIRECTIONAL:		// This can happen if a buggy application does a scsi passthru		// and sets both inlen and outlen to non-zero. ( see		// ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() )	  	cp->Request.Type.Direction = XFER_RSVD;		// This is technically wrong, and cciss controllers should		// reject it with CMD_INVALID, which is the most correct 		// response, but non-fibre backends appear to let it 		// slide by, and give the same results as if this field		// were set correctly.  Either way is acceptable for		// our purposes here.		break;	  default: 		printk("cciss: unknown data direction: %d\n", 			cmd->sc_data_direction);		BUG();		break;	}	cciss_scatter_gather((*c)->pdev, cp, cmd); // Fill the SG list	/* Put the request on the tail of the request queue */	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);	addQ(&(*c)->reqQ, cp);	(*c)->Qdepth++;	start_io(*c);	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);	/* the cmd'll come back via intr handler in complete_scsi_command()  */	return 0;}static void cciss_unregister_scsi(int ctlr){	struct cciss_scsi_adapter_data_t *sa;	struct cciss_scsi_cmd_stack_t *stk;	unsigned long flags;	/* we are being forcibly unloaded, and may not refuse. */	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);	sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;	stk = &sa->cmd_stack; 	/* if we weren't ever actually registered, don't unregister */ 	if (sa->registered) {		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);		scsi_remove_host(sa->scsi_host);		scsi_host_put(sa->scsi_host);		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);	}	/* set scsi_host to NULL so our detect routine will 	   find us on register */	sa->scsi_host = NULL;	scsi_cmd_stack_free(ctlr);	kfree(sa);	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);}static int cciss_register_scsi(int ctlr){	unsigned long flags;	CPQ_TAPE_LOCK(ctlr, flags);	/* Since this is really a block driver, the SCSI core may not be 	   initialized at init time, in which case, calling scsi_register_host	   would hang.  Instead, we do it later, via /proc filesystem	   and rc scripts, when we know SCSI core is good to go. */	/* Only register if SCSI devices are detected. */	if (ccissscsi[ctlr].ndevices != 0) {		((struct cciss_scsi_adapter_data_t *) 			hba[ctlr]->scsi_ctlr)->registered = 1;		CPQ_TAPE_UNLOCK(ctlr, flags);		return cciss_scsi_detect(ctlr);	}	CPQ_TAPE_UNLOCK(ctlr, flags);	printk(KERN_INFO 		"cciss%d: No appropriate SCSI device detected, "		"SCSI subsystem not engaged.\n", ctlr);	return 0;}static int cciss_engage_scsi(int ctlr){	struct cciss_scsi_adapter_data_t *sa;	struct cciss_scsi_cmd_stack_t *stk;	unsigned long flags;	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);	sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;	stk = &sa->cmd_stack; 	if (((struct cciss_scsi_adapter_data_t *) 		hba[ctlr]->scsi_ctlr)->registered) {		printk("cciss%d: SCSI subsystem already engaged.\n", ctlr);		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);		return ENXIO;	}	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);	cciss_update_non_disk_devices(ctlr, -1);	cciss_register_scsi(ctlr);	return 0;}static voidcciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len){	unsigned long flags;	int size;	*pos = *pos -1; *len = *len - 1; // cut off the last trailing newline	CPQ_TAPE_LOCK(ctlr, flags);	size = sprintf(buffer + *len, 		"Sequential access devices: %d\n\n",			ccissscsi[ctlr].ndevices);	CPQ_TAPE_UNLOCK(ctlr, flags);	*pos += size; *len += size;}#else /* no CONFIG_CISS_SCSI_TAPE *//* If no tape support, then these become defined out of existence */#define cciss_scsi_setup(cntl_num)#define cciss_unregister_scsi(ctlr)#define cciss_register_scsi(ctlr)#define cciss_proc_tape_report(ctlr, buffer, pos, len)#endif /* CONFIG_CISS_SCSI_TAPE */

⌨️ 快捷键说明

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