cciss_scsi.c

来自「linux 内核源代码」· C语言 代码 · 共 1,504 行 · 第 1/3 页

C
1,504
字号
	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 = kzalloc(reportlunsize, GFP_KERNEL);	if (ld_buff == NULL) {		printk(KERN_ERR "cciss: out of memory\n");		return;	}	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,					scsi_device_type(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 len;	struct scatterlist *sg;	__u64 addr64;	int use_sg, i;	BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);	use_sg = scsi_dma_map(cmd);	if (use_sg) {	/* not too many addrs? */		scsi_for_each_sg(cmd, sg, use_sg, i) {			addr64 = (__u64) sg_dma_address(sg);			len  = sg_dma_len(sg);			cp->SG[i].Addr.lower =				(__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);			cp->SG[i].Addr.upper =				(__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);			cp->SG[i].Len = len;			cp->SG[i].Ext = 0;  // we are not chaining		}	}	cp->Header.SGList = (__u8) use_sg;   /* no. SGs contig in this cmd */	cp->Header.SGTotal = (__u16) use_sg; /* 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));	BUG_ON(cmd->cmd_len > sizeof(cp->Request.CDB));	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;}/* Need at least one of these error handlers to keep ../scsi/hosts.c from  * complaining.  Doing a host- or bus-reset can't do anything good here.  * Despite what it might say in scsi_error.c, there may well be commands * on the controller, as the cciss driver registers twice, once as a block * device for the logical drives, and once as a scsi device, for any tape * drives.  So we know there are no commands out on the tape drives, but we * don't know there are no commands on the controller, and it is likely  * that there probably are, as the cciss block device is most commonly used * as a boot device (embedded controller on HP/Compaq systems.)*/static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd){	int rc;	CommandList_struct *cmd_in_trouble;	ctlr_info_t **c;	int ctlr;	/* find the controller to which the command to be aborted was sent */	c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];		if (c == NULL) /* paranoia */		return FAILED;	ctlr = (*c)->ctlr;	printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr);	/* find the command that's giving us trouble */	cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble;	if (cmd_in_trouble == NULL) { /* paranoia */		return FAILED;	}	/* send a reset to the SCSI LUN which the command was sent to */	rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, 		(unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 		TYPE_MSG);	/* sendcmd turned off interrputs on the board, turn 'em back on. */	(*c)->access.set_intr_mask(*c, CCISS_INTR_ON);	if (rc == 0)		return SUCCESS;	printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr);	return FAILED;}static int  cciss_eh_abort_handler(struct scsi_cmnd *scsicmd){	int rc;	CommandList_struct *cmd_to_abort;	ctlr_info_t **c;	int ctlr;	/* find the controller to which the command to be aborted was sent */	c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];		if (c == NULL) /* paranoia */		return FAILED;	ctlr = (*c)->ctlr;	printk(KERN_WARNING "cciss%d: aborting tardy SCSI cmd\n", ctlr);	/* find the command to be aborted */	cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble;	if (cmd_to_abort == NULL) /* paranoia */		return FAILED;	rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, 		0, 2, 0, 0, 		(unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0], 		TYPE_MSG);	/* sendcmd turned off interrputs on the board, turn 'em back on. */	(*c)->access.set_intr_mask(*c, CCISS_INTR_ON);	if (rc == 0)		return SUCCESS;	return FAILED;}#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 + =
减小字号Ctrl + -
显示快捷键?