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

📄 i2o_scsi.c

📁 h内核
💻 C
📖 第 1 页 / 共 2 页
字号:
			switch (as) {			case 0x0E:				/* SCSI Reset */				cmd->result = DID_RESET << 16;				break;			case 0x0F:				cmd->result = DID_PARITY << 16;				break;			default:				cmd->result = DID_ERROR << 16;				break;			}			break;		}		cmd->scsi_done(cmd);		return 1;	}	cmd->result = DID_OK << 16 | ds;	cmd->scsi_done(cmd);	dev = &c->pdev->dev;	if (cmd->use_sg)		dma_unmap_sg(dev, (struct scatterlist *)cmd->buffer,			     cmd->use_sg, cmd->sc_data_direction);	else if (cmd->request_bufflen)		dma_unmap_single(dev, (dma_addr_t) ((long)cmd->SCp.ptr),				 cmd->request_bufflen, cmd->sc_data_direction);	return 1;};/** *	i2o_scsi_notify_controller_add - Retrieve notifications of added *					 controllers *	@c: the controller which was added * *	If a I2O controller is added, we catch the notification to add a *	corresponding Scsi_Host. */static void i2o_scsi_notify_controller_add(struct i2o_controller *c){	struct i2o_scsi_host *i2o_shost;	int rc;	i2o_shost = i2o_scsi_host_alloc(c);	if (IS_ERR(i2o_shost)) {		osm_err("Could not initialize SCSI host\n");		return;	}	rc = scsi_add_host(i2o_shost->scsi_host, &c->device);	if (rc) {		osm_err("Could not add SCSI host\n");		scsi_host_put(i2o_shost->scsi_host);		return;	}	c->driver_data[i2o_scsi_driver.context] = i2o_shost;	osm_debug("new I2O SCSI host added\n");};/** *	i2o_scsi_notify_controller_remove - Retrieve notifications of removed *					    controllers *	@c: the controller which was removed * *	If a I2O controller is removed, we catch the notification to remove the *	corresponding Scsi_Host. */static void i2o_scsi_notify_controller_remove(struct i2o_controller *c){	struct i2o_scsi_host *i2o_shost;	i2o_shost = i2o_scsi_get_host(c);	if (!i2o_shost)		return;	c->driver_data[i2o_scsi_driver.context] = NULL;	scsi_remove_host(i2o_shost->scsi_host);	scsi_host_put(i2o_shost->scsi_host);	pr_info("I2O SCSI host removed\n");};/* SCSI OSM driver struct */static struct i2o_driver i2o_scsi_driver = {	.name = OSM_NAME,	.reply = i2o_scsi_reply,	.classes = i2o_scsi_class_id,	.notify_controller_add = i2o_scsi_notify_controller_add,	.notify_controller_remove = i2o_scsi_notify_controller_remove,	.driver = {		   .probe = i2o_scsi_probe,		   .remove = i2o_scsi_remove,		   },};/** *	i2o_scsi_queuecommand - queue a SCSI command *	@SCpnt: scsi command pointer *	@done: callback for completion * *	Issue a scsi command asynchronously. Return 0 on success or 1 if *	we hit an error (normally message queue congestion). The only *	minor complication here is that I2O deals with the device addressing *	so we have to map the bus/dev/lun back to an I2O handle as well *	as faking absent devices ourself. * *	Locks: takes the controller lock on error path only */static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,				 void (*done) (struct scsi_cmnd *)){	struct i2o_controller *c;	struct Scsi_Host *host;	struct i2o_device *i2o_dev;	struct device *dev;	int tid;	struct i2o_message __iomem *msg;	u32 m;	u32 scsi_flags, sg_flags;	u32 __iomem *mptr;	u32 __iomem *lenptr;	u32 len, reqlen;	int i;	/*	 *      Do the incoming paperwork	 */	i2o_dev = SCpnt->device->hostdata;	host = SCpnt->device->host;	c = i2o_dev->iop;	dev = &c->pdev->dev;	SCpnt->scsi_done = done;	if (unlikely(!i2o_dev)) {		osm_warn("no I2O device in request\n");		SCpnt->result = DID_NO_CONNECT << 16;		done(SCpnt);		return 0;	}	tid = i2o_dev->lct_data.tid;	osm_debug("qcmd: Tid = %03x\n", tid);	osm_debug("Real scsi messages.\n");	/*	 *      Obtain an I2O message. If there are none free then	 *      throw it back to the scsi layer	 */	m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);	if (m == I2O_QUEUE_EMPTY)		return SCSI_MLQUEUE_HOST_BUSY;	/*	 *      Put together a scsi execscb message	 */	len = SCpnt->request_bufflen;	switch (SCpnt->sc_data_direction) {	case PCI_DMA_NONE:		scsi_flags = 0x00000000;	// DATA NO XFER		sg_flags = 0x00000000;		break;	case PCI_DMA_TODEVICE:		scsi_flags = 0x80000000;	// DATA OUT (iop-->dev)		sg_flags = 0x14000000;		break;	case PCI_DMA_FROMDEVICE:		scsi_flags = 0x40000000;	// DATA IN  (iop<--dev)		sg_flags = 0x10000000;		break;	default:		/* Unknown - kill the command */		SCpnt->result = DID_NO_CONNECT << 16;		done(SCpnt);		return 0;	}	writel(I2O_CMD_SCSI_EXEC << 24 | HOST_TID << 12 | tid, &msg->u.head[1]);	writel(i2o_scsi_driver.context, &msg->u.s.icntxt);	/* We want the SCSI control block back */	writel(i2o_cntxt_list_add(c, SCpnt), &msg->u.s.tcntxt);	/* LSI_920_PCI_QUIRK	 *	 *      Intermittant observations of msg frame word data corruption	 *      observed on msg[4] after:	 *        WRITE, READ-MODIFY-WRITE	 *      operations.  19990606 -sralston	 *	 *      (Hence we build this word via tag. Its good practice anyway	 *       we don't want fetches over PCI needlessly)	 */	/* Attach tags to the devices */	/*	   if(SCpnt->device->tagged_supported) {	   if(SCpnt->tag == HEAD_OF_QUEUE_TAG)	   scsi_flags |= 0x01000000;	   else if(SCpnt->tag == ORDERED_QUEUE_TAG)	   scsi_flags |= 0x01800000;	   }	 */	/* Direction, disconnect ok, tag, CDBLen */	writel(scsi_flags | 0x20200000 | SCpnt->cmd_len, &msg->body[0]);	mptr = &msg->body[1];	/* Write SCSI command into the message - always 16 byte block */	memcpy_toio(mptr, SCpnt->cmnd, 16);	mptr += 4;	lenptr = mptr++;	/* Remember me - fill in when we know */	reqlen = 12;		// SINGLE SGE	/* Now fill in the SGList and command */	if (SCpnt->use_sg) {		struct scatterlist *sg;		int sg_count;		sg = SCpnt->request_buffer;		len = 0;		sg_count = dma_map_sg(dev, sg, SCpnt->use_sg,				      SCpnt->sc_data_direction);		if (unlikely(sg_count <= 0))			return -ENOMEM;		for (i = SCpnt->use_sg; i > 0; i--) {			if (i == 1)				sg_flags |= 0xC0000000;			writel(sg_flags | sg_dma_len(sg), mptr++);			writel(sg_dma_address(sg), mptr++);			len += sg_dma_len(sg);			sg++;		}		reqlen = mptr - &msg->u.head[0];		writel(len, lenptr);	} else {		len = SCpnt->request_bufflen;		writel(len, lenptr);		if (len > 0) {			dma_addr_t dma_addr;			dma_addr = dma_map_single(dev, SCpnt->request_buffer,						  SCpnt->request_bufflen,						  SCpnt->sc_data_direction);			if (!dma_addr)				return -ENOMEM;			SCpnt->SCp.ptr = (void *)(unsigned long)dma_addr;			sg_flags |= 0xC0000000;			writel(sg_flags | SCpnt->request_bufflen, mptr++);			writel(dma_addr, mptr++);		} else			reqlen = 9;	}	/* Stick the headers on */	writel(reqlen << 16 | SGL_OFFSET_10, &msg->u.head[0]);	/* Queue the message */	i2o_msg_post(c, m);	osm_debug("Issued %ld\n", SCpnt->serial_number);	return 0;};/** *	i2o_scsi_abort - abort a running command *	@SCpnt: command to abort * *	Ask the I2O controller to abort a command. This is an asynchrnous *	process and our callback handler will see the command complete with an *	aborted message if it succeeds. * *	Returns 0 if the command is successfully aborted or negative error code *	on failure. */static int i2o_scsi_abort(struct scsi_cmnd *SCpnt){	struct i2o_device *i2o_dev;	struct i2o_controller *c;	struct i2o_message __iomem *msg;	u32 m;	int tid;	int status = FAILED;	osm_warn("Aborting command block.\n");	i2o_dev = SCpnt->device->hostdata;	c = i2o_dev->iop;	tid = i2o_dev->lct_data.tid;	m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);	if (m == I2O_QUEUE_EMPTY)		return SCSI_MLQUEUE_HOST_BUSY;	writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);	writel(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid,	       &msg->u.head[1]);	writel(i2o_cntxt_list_get_ptr(c, SCpnt), &msg->body[0]);	if (i2o_msg_post_wait(c, m, I2O_TIMEOUT_SCSI_SCB_ABORT))		status = SUCCESS;	return status;}/** *	i2o_scsi_bios_param	-	Invent disk geometry *	@sdev: scsi device *	@dev: block layer device *	@capacity: size in sectors *	@ip: geometry array * *	This is anyones guess quite frankly. We use the same rules everyone *	else appears to and hope. It seems to work. */static int i2o_scsi_bios_param(struct scsi_device *sdev,			       struct block_device *dev, sector_t capacity,			       int *ip){	int size;	size = capacity;	ip[0] = 64;		/* heads                        */	ip[1] = 32;		/* sectors                      */	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */		ip[0] = 255;	/* heads                        */		ip[1] = 63;	/* sectors                      */		ip[2] = size / (255 * 63);	/* cylinders                    */	}	return 0;}static struct scsi_host_template i2o_scsi_host_template = {	.proc_name = OSM_NAME,	.name = OSM_DESCRIPTION,	.info = i2o_scsi_info,	.queuecommand = i2o_scsi_queuecommand,	.eh_abort_handler = i2o_scsi_abort,	.bios_param = i2o_scsi_bios_param,	.can_queue = I2O_SCSI_CAN_QUEUE,	.sg_tablesize = 8,	.cmd_per_lun = 6,	.use_clustering = ENABLE_CLUSTERING,};/** *	i2o_scsi_init - SCSI OSM initialization function * *	Register SCSI OSM into I2O core. * *	Returns 0 on success or negative error code on failure. */static int __init i2o_scsi_init(void){	int rc;	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");	/* Register SCSI OSM into I2O core */	rc = i2o_driver_register(&i2o_scsi_driver);	if (rc) {		osm_err("Could not register SCSI driver\n");		return rc;	}	return 0;};/** *	i2o_scsi_exit - SCSI OSM exit function * *	Unregisters SCSI OSM from I2O core. */static void __exit i2o_scsi_exit(void){	/* Unregister I2O SCSI OSM from I2O core */	i2o_driver_unregister(&i2o_scsi_driver);};MODULE_AUTHOR("Red Hat Software");MODULE_LICENSE("GPL");MODULE_DESCRIPTION(OSM_DESCRIPTION);MODULE_VERSION(OSM_VERSION);module_init(i2o_scsi_init);module_exit(i2o_scsi_exit);

⌨️ 快捷键说明

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