mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* Re: [PATCH] 2.5.63 cciss fix unlikely startup problem
@ 2003-02-27  8:39 Stephen Cameron
  0 siblings, 0 replies; 5+ messages in thread
From: Stephen Cameron @ 2003-02-27  8:39 UTC (permalink / raw)
  To: linux-kernel

Another cciss patch for 2.5.63

Add new big passthrough ioctl to allow large buffers.
Used by e.g. online array controller firmware flash utility.

-- steve

--- linux-2.5.63/drivers/block/cciss.c~bigioctl	2003-02-27 14:11:56.000000000 +0600
+++ linux-2.5.63-scameron/drivers/block/cciss.c	2003-02-27 14:11:56.000000000 +0600
@@ -728,7 +728,153 @@ static int cciss_ioctl(struct inode *ino
 		cmd_free(h, c, 0);
                 return(0);
 	} 
-
+	case CCISS_BIG_PASSTHRU: {
+		BIG_IOCTL_Command_struct *ioc;
+		ctlr_info_t *h = hba[ctlr];
+		CommandList_struct *c;
+		unsigned char **buff = NULL;
+		int	*buff_size = NULL;
+		u64bit	temp64;
+		unsigned long flags;
+		BYTE sg_used = 0;
+		int status = 0;
+		int i;
+		DECLARE_COMPLETION(wait);
+		__u32   left;
+		__u32	sz;
+		BYTE    *data_ptr;
+
+		if (!arg)
+			return -EINVAL;
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		ioc = (BIG_IOCTL_Command_struct *) 
+			kmalloc(sizeof(*ioc), GFP_KERNEL);
+		if (!ioc) {
+			status = -ENOMEM;
+			goto cleanup1;
+		}
+		if (copy_from_user(ioc, (void *) arg, sizeof(*ioc)))
+			return -EFAULT;
+		if ((ioc->buf_size < 1) &&
+			(ioc->Request.Type.Direction != XFER_NONE))
+				return -EINVAL;
+		/* Check kmalloc limits  using all SGs */
+		if (ioc->malloc_size > MAX_KMALLOC_SIZE)
+			return -EINVAL;
+		if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES)
+			return -EINVAL;
+		buff = (unsigned char **) kmalloc(MAXSGENTRIES * 
+				sizeof(char *), GFP_KERNEL);
+		if (!buff) {
+			status = -ENOMEM;
+			goto cleanup1;
+		}
+		memset(buff, 0, MAXSGENTRIES);
+		buff_size = (int *) kmalloc(MAXSGENTRIES * sizeof(int), 
+					GFP_KERNEL);
+		if (!buff_size) {
+			status = -ENOMEM;
+			goto cleanup1;
+		}
+		left = ioc->buf_size;
+		data_ptr = (BYTE *) ioc->buf;
+		while (left) {
+			sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
+			buff_size[sg_used] = sz;
+			buff[sg_used] = kmalloc(sz, GFP_KERNEL);
+			if (buff[sg_used] == NULL) {
+				status = -ENOMEM;
+				goto cleanup1;
+			}
+			if (ioc->Request.Type.Direction == XFER_WRITE &&
+				copy_from_user(buff[sg_used], data_ptr, sz)) {
+					status = -ENOMEM;
+					goto cleanup1;			
+			}
+			left -= sz;
+			data_ptr += sz;
+			sg_used++;
+		}
+		if ((c = cmd_alloc(h , 0)) == NULL) {
+			status = -ENOMEM;
+			goto cleanup1;	
+		}
+		c->cmd_type = CMD_IOCTL_PEND;
+		c->Header.ReplyQueue = 0;
+		
+		if( ioc->buf_size > 0) {
+			c->Header.SGList = sg_used;
+			c->Header.SGTotal= sg_used;
+		} else { 
+			c->Header.SGList = 0;
+			c->Header.SGTotal= 0;
+		}
+		c->Header.LUN = ioc->LUN_info;
+		c->Header.Tag.lower = c->busaddr;
+		
+		c->Request = ioc->Request;
+		if (ioc->buf_size > 0 ) {
+			int i;
+			for(i=0; i<sg_used; i++) {
+				temp64.val = pci_map_single( h->pdev, buff[i],
+					buff_size[i],
+					PCI_DMA_BIDIRECTIONAL);
+				c->SG[i].Addr.lower = temp64.val32.lower;
+				c->SG[i].Addr.upper = temp64.val32.upper;
+				c->SG[i].Len = buff_size[i];
+				c->SG[i].Ext = 0;  /* we are not chaining */
+			}
+		}
+		c->waiting = &wait;
+		/* Put the request on the tail of the request queue */
+		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+		addQ(&h->reqQ, c);
+		h->Qdepth++;
+		start_io(h);
+		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+		wait_for_completion(&wait);
+		/* unlock the buffers from DMA */
+		for(i=0; i<sg_used; i++) {
+			temp64.val32.lower = c->SG[i].Addr.lower;
+			temp64.val32.upper = c->SG[i].Addr.upper;
+			pci_unmap_single( h->pdev, (dma_addr_t) temp64.val,
+				buff_size[i], PCI_DMA_BIDIRECTIONAL);
+		}
+		/* Copy the error information out */
+		ioc->error_info = *(c->err_info);
+		if (copy_to_user((void *) arg, ioc, sizeof(*ioc))) {
+			cmd_free(h, c, 0);
+			status = -EFAULT;
+			goto cleanup1;
+		}
+		if (ioc->Request.Type.Direction == XFER_READ) {
+			/* Copy the data out of the buffer we created */
+			BYTE *ptr = (BYTE  *) ioc->buf;
+	        	for(i=0; i< sg_used; i++) {
+				if (copy_to_user(ptr, buff[i], buff_size[i])) {
+					cmd_free(h, c, 0);
+					status = -EFAULT;
+					goto cleanup1;
+				}
+				ptr += buff_size[i];
+			}
+		}
+		cmd_free(h, c, 0);
+		status = 0;
+cleanup1:
+		if (buff) {
+			for(i=0; i<sg_used; i++)
+				if(buff[i] != NULL)
+					kfree(buff[i]);
+			kfree(buff);
+		}
+		if (buff_size)
+			kfree(buff_size);
+		if (ioc)
+			kfree(ioc);
+		return(status);
+	}
 	default:
 		return -EBADRQC;
 	}
--- linux-2.5.63/include/linux/cciss_ioctl.h~bigioctl	2003-02-27 14:11:56.000000000 +0600
+++ linux-2.5.63-scameron/include/linux/cciss_ioctl.h	2003-02-27 14:11:56.000000000 +0600
@@ -33,6 +33,18 @@ typedef __u32 BusTypes_type;
 typedef char FirmwareVer_type[4];
 typedef __u32 DriverVer_type;
 
+#define MAX_KMALLOC_SIZE 128000
+
+typedef struct _BIG_IOCTL_Command_struct {
+  LUNAddr_struct	   LUN_info;
+  RequestBlock_struct      Request;
+  ErrorInfo_struct  	   error_info; 
+  DWORD			   malloc_size; /* < MAX_KMALLOC_SIZE in cciss.c */
+  DWORD			   buf_size;    /* size in bytes of the buf */
+  				        /* < malloc_size * MAXSGENTRIES */
+  BYTE			   *buf;
+} BIG_IOCTL_Command_struct;
+
 
 #ifndef CCISS_CMD_H
 // This defines are duplicated in cciss_cmd.h in the driver directory 
@@ -196,5 +208,6 @@ typedef struct _LogvolInfo_struct{
 
 #define CCISS_REGNEWD	   _IO(CCISS_IOC_MAGIC, 14)
 #define CCISS_GETLUNINFO   _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct)
+#define CCISS_BIG_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 18, BIG_IOCTL_Command_struct)
 
 #endif  

_

^ permalink raw reply	[flat|nested] 5+ messages in thread
* Re: [PATCH] 2.5.63 cciss fix unlikely startup problem
@ 2003-02-27  8:36 Stephen Cameron
  0 siblings, 0 replies; 5+ messages in thread
From: Stephen Cameron @ 2003-02-27  8:36 UTC (permalink / raw)
  To: linux-kernel

Another cciss patch for 2.5.63

Add CCISS_GETLUNINFO ioctl.

This ioctl returns the LUNID, number of partitions, and current 
number of opens on a logical volume.   Used by the array config utility
or any app that needs to send passthrough commands to a particular 
logical disk.

-- steve

--- linux-2.5.63/drivers/block/cciss.c~getluninfo_ioctl	2003-02-27 14:11:51.000000000 +0600
+++ linux-2.5.63-scameron/drivers/block/cciss.c	2003-02-27 14:11:51.000000000 +0600
@@ -589,6 +589,24 @@ static int cciss_ioctl(struct inode *ino
 	case CCISS_REVALIDVOLS:
                 return( revalidate_allvol(inode->i_rdev));
 
+ 	case CCISS_GETLUNINFO: {
+ 		LogvolInfo_struct luninfo;
+ 		struct gendisk *disk = hba[ctlr]->gendisk[dsk];
+ 		drive_info_struct *drv = &hba[ctlr]->drv[dsk];
+ 		int i;
+ 		
+ 		luninfo.LunID = drv->LunID;
+ 		luninfo.num_opens = drv->usage_count;
+ 		luninfo.num_parts = 0;
+ 		/* count partitions 1 to 15 with sizes > 0 */
+ 		for(i=1; i <MAX_PART; i++)
+ 			if (disk->part[i].nr_sects != 0)
+ 				luninfo.num_parts++;
+ 		if (copy_to_user((void *) arg, &luninfo,
+ 				sizeof(LogvolInfo_struct)))
+ 			return -EFAULT;
+ 		return(0);
+ 	}
 	case CCISS_DEREGDISK:
 		return( deregister_disk(ctlr,dsk));
 
--- linux-2.5.63/include/linux/cciss_ioctl.h~getluninfo_ioctl	2003-02-27 14:11:51.000000000 +0600
+++ linux-2.5.63-scameron/include/linux/cciss_ioctl.h	2003-02-27 14:11:51.000000000 +0600
@@ -169,6 +169,11 @@ typedef struct _IOCTL_Command_struct {
   BYTE			   *buf;
 } IOCTL_Command_struct;
 
+typedef struct _LogvolInfo_struct{
+	__u32	LunID;
+	int	num_opens;  /* number of opens on the logical volume */
+	int	num_parts;  /* number of partitions configured on logvol */
+} LogvolInfo_struct;
 
 #define CCISS_GETPCIINFO _IOR(CCISS_IOC_MAGIC, 1, cciss_pci_info_struct)
 
@@ -190,5 +195,6 @@ typedef struct _IOCTL_Command_struct {
 #define CCISS_REGNEWDISK  _IOW(CCISS_IOC_MAGIC, 13, int)
 
 #define CCISS_REGNEWD	   _IO(CCISS_IOC_MAGIC, 14)
+#define CCISS_GETLUNINFO   _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct)
 
 #endif  

_

^ permalink raw reply	[flat|nested] 5+ messages in thread
* Re: [PATCH] 2.5.63 cciss fix unlikely startup problem
@ 2003-02-27  8:24 Stephen Cameron
  0 siblings, 0 replies; 5+ messages in thread
From: Stephen Cameron @ 2003-02-27  8:24 UTC (permalink / raw)
  To: linux-kernel

Another cciss patch for 2.5.63

* add cmd_type to sendcmd parameters to allow scsi messages to be
  sent down.
* factor out duplicated code into fill_cmd function.

-- steve

--- linux-2.5.63/drivers/block/cciss.c~sendcmd_cleanup	2003-02-27 13:11:23.000000000 +0600
+++ linux-2.5.63-scameron/drivers/block/cciss.c	2003-02-27 14:11:19.000000000 +0600
@@ -132,7 +132,7 @@ static inline void addQ(CommandList_stru
 static void start_io( ctlr_info_t *h);
 static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size,
 	unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
-	unsigned char *scsi3addr);
+	unsigned char *scsi3addr, int cmd_type);
 
 #ifdef CONFIG_PROC_FS
 static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
@@ -830,112 +830,152 @@ static int deregister_disk(int ctlr, int
 	h->drv[logvol].LunID = 0;
 	return(0);
 }
-static int sendcmd_withirq(__u8	cmd,
-	int	ctlr,
-	void	*buff,
-	size_t	size,
-	unsigned int use_unit_num,
-	unsigned int log_unit,
-	__u8	page_code )
+static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
+	size_t size,
+	unsigned int use_unit_num, /* 0: address the controller,
+				      1: address logical volume log_unit,
+				      2: periph device address is scsi3addr */
+	unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr,
+	int cmd_type)
 {
-	ctlr_info_t *h = hba[ctlr];
-	CommandList_struct *c;
-	u64bit	buff_dma_handle;
-	unsigned long flags;
-	int return_status = IO_OK;
-	DECLARE_COMPLETION(wait);
-	
-	if ((c = cmd_alloc(h , 0)) == NULL)
-	{
-		return -ENOMEM;
-	}
-	// Fill in the command type 
+	ctlr_info_t *h= hba[ctlr];
+	u64bit buff_dma_handle;
+	int status = IO_OK;
+
 	c->cmd_type = CMD_IOCTL_PEND;
-	// Fill in Command Header 
-	c->Header.ReplyQueue = 0;  // unused in simple mode
-	if( buff != NULL) 	// buffer to fill 
-	{
+	c->Header.ReplyQueue = 0;
+	if( buff != NULL) {
 		c->Header.SGList = 1;
 		c->Header.SGTotal= 1;
-	} else	// no buffers to fill  
-	{
+	} else {
 		c->Header.SGList = 0;
                 c->Header.SGTotal= 0;
 	}
-	c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
-	// Fill in Request block 	
-	switch(cmd)
-	{
+	c->Header.Tag.lower = c->busaddr;
+
+	c->Request.Type.Type = cmd_type;
+	if (cmd_type == TYPE_CMD) {
+		switch(cmd) {
 		case  CISS_INQUIRY:
 			/* If the logical unit number is 0 then, this is going
-				to controller so It's a physical command
-				mode = 0 target = 0.
-				So we have nothing to write. 
-				Otherwise 
-				mode = 1  target = LUNID
-			*/
-			if(use_unit_num != 0)
-			{
+			to controller so It's a physical command
+			mode = 0 target = 0.  So we have nothing to write.
+			otherwise, if use_unit_num == 1,
+			mode = 1(volume set addressing) target = LUNID
+			otherwise, if use_unit_num == 2,
+			mode = 0(periph dev addr) target = scsi3addr */
+			if (use_unit_num == 1) {
 				c->Header.LUN.LogDev.VolId=
-                                	hba[ctlr]->drv[log_unit].LunID;
+					h->drv[log_unit].LunID;
                         	c->Header.LUN.LogDev.Mode = 1;
+			} else if (use_unit_num == 2) {
+				memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
+				c->Header.LUN.LogDev.Mode = 0;
 			}
-			if(page_code != 0)
-			{
+			/* are we trying to read a vital product page */
+			if(page_code != 0) {
 				c->Request.CDB[1] = 0x01;
 				c->Request.CDB[2] = page_code;
 			}
 			c->Request.CDBLen = 6;
-			c->Request.Type.Type =  TYPE_CMD; // It is a command. 
 			c->Request.Type.Attribute = ATTR_SIMPLE;  
-			c->Request.Type.Direction = XFER_READ; // Read 
-			c->Request.Timeout = 0; // Don't time out 
+			c->Request.Type.Direction = XFER_READ;
+			c->Request.Timeout = 0;
 			c->Request.CDB[0] =  CISS_INQUIRY;
 			c->Request.CDB[4] = size  & 0xFF;  
 		break;
-	case CISS_REPORT_LOG:
+		case CISS_REPORT_LOG:
+		case CISS_REPORT_PHYS:
                         /* Talking to controller so It's a physical command
-                                mode = 00 target = 0.
-                                So we have nothing to write.
+			   mode = 00 target = 0.  Nothing to write.
                         */
-                        c->Request.CDBLen = 12;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
-                        c->Request.Type.Attribute = ATTR_SIMPLE; 
-                        c->Request.Type.Direction = XFER_READ; // Read
-                        c->Request.Timeout = 0; // Don't time out
-                        c->Request.CDB[0] = CISS_REPORT_LOG;
-                        c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
-                        c->Request.CDB[7] = (size >> 16) & 0xFF;
-                        c->Request.CDB[8] = (size >> 8) & 0xFF;
-                        c->Request.CDB[9] = size & 0xFF;
-                break;
-	case CCISS_READ_CAPACITY:
-			c->Header.LUN.LogDev.VolId= 
-				hba[ctlr]->drv[log_unit].LunID;
+			c->Request.CDBLen = 12;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_READ;
+			c->Request.Timeout = 0;
+			c->Request.CDB[0] = cmd;
+			c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
+			c->Request.CDB[7] = (size >> 16) & 0xFF;
+			c->Request.CDB[8] = (size >> 8) & 0xFF;
+			c->Request.CDB[9] = size & 0xFF;
+			break;
+
+		case CCISS_READ_CAPACITY:
+			c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID;
 			c->Header.LUN.LogDev.Mode = 1;
 			c->Request.CDBLen = 10;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
-                        c->Request.Type.Attribute = ATTR_SIMPLE; 
-                        c->Request.Type.Direction = XFER_READ; // Read
-                        c->Request.Timeout = 0; // Don't time out
-                        c->Request.CDB[0] = CCISS_READ_CAPACITY;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_READ;
+			c->Request.Timeout = 0;
+			c->Request.CDB[0] = cmd;
+		break;
+		case CCISS_CACHE_FLUSH:
+			c->Request.CDBLen = 12;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_WRITE;
+			c->Request.Timeout = 0;
+			c->Request.CDB[0] = BMIC_WRITE;
+			c->Request.CDB[6] = BMIC_CACHE_FLUSH;
 		break;
 		default:
 			printk(KERN_WARNING
-				"cciss:  Unknown Command 0x%c sent attempted\n", cmd);
-			cmd_free(h, c, 1);
+				"cciss%d:  Unknown Command 0x%c\n", ctlr, cmd);
 			return(IO_ERROR);
-	};
-
-	// Fill in the scatter gather information
-	if (size > 0 ) 
-	{
-		buff_dma_handle.val = (__u64) pci_map_single( h->pdev, 
+		}
+	} else if (cmd_type == TYPE_MSG) {
+		switch (cmd) {
+		case 3:	/* No-Op message */
+			c->Request.CDBLen = 1;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_WRITE;
+			c->Request.Timeout = 0;
+			c->Request.CDB[0] = cmd;
+			break;
+		default:
+			printk(KERN_WARNING
+				"cciss%d: unknown message type %d\n",
+				ctlr, cmd);
+			return IO_ERROR;
+		}
+	} else {
+		printk(KERN_WARNING
+			"cciss%d: unknown command type %d\n", ctlr, cmd_type);
+		return IO_ERROR;
+	}
+	/* Fill in the scatter gather information */
+	if (size > 0) {
+		buff_dma_handle.val = (__u64) pci_map_single(h->pdev,
 			buff, size, PCI_DMA_BIDIRECTIONAL);
 		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
 		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
 		c->SG[0].Len = size;
-		c->SG[0].Ext = 0;  // we are not chaining
+		c->SG[0].Ext = 0;  /* we are not chaining */
+	}
+	return status;
+}
+static int sendcmd_withirq(__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int use_unit_num,
+	unsigned int log_unit,
+	__u8	page_code,
+	int cmd_type)
+{
+	ctlr_info_t *h = hba[ctlr];
+	CommandList_struct *c;
+	u64bit	buff_dma_handle;
+	unsigned long flags;
+	int return_status;
+	DECLARE_COMPLETION(wait);
+	
+	if ((c = cmd_alloc(h , 0)) == NULL)
+		return -ENOMEM;
+	return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
+		log_unit, page_code, NULL, cmd_type);
+	if (return_status != IO_OK) {
+		cmd_free(h, c, 0);
+		return return_status;
 	}
 resend_cmd2:
 	c->waiting = &wait;
@@ -1040,10 +1080,10 @@ static void cciss_geometry_inquiry(int c
 	memset(inq_buff, 0, sizeof(InquiryData_struct));
 	if (withirq)
 		return_code = sendcmd_withirq(CISS_INQUIRY, ctlr,
-			inq_buff, sizeof(*inq_buff), 1, logvol ,0xC1);
+			inq_buff, sizeof(*inq_buff), 1, logvol ,0xC1, TYPE_CMD);
 	else
 		return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff,
-			sizeof(*inq_buff), 1, logvol ,0xC1, NULL);
+			sizeof(*inq_buff), 1, logvol ,0xC1, NULL, TYPE_CMD);
 	if (return_code == IO_OK) {
 		if(inq_buff->data_byte[8] == 0xFF) {
 			printk(KERN_WARNING
@@ -1082,10 +1122,10 @@ cciss_read_capacity(int ctlr, int logvol
 	memset(buf, 0, sizeof(*buf));
 	if (withirq)
 		return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
-			ctlr, buf, sizeof(*buf), 1, logvol, 0 );
+			ctlr, buf, sizeof(*buf), 1, logvol, 0, TYPE_CMD);
 	else
 		return_code = sendcmd(CCISS_READ_CAPACITY,
-			ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL );
+			ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD);
 	if (return_code == IO_OK) {
 		*total_size = be32_to_cpu(*((__u32 *) &buf->total_size[0]))+1;
 		*block_size = be32_to_cpu(*((__u32 *) &buf->block_size[0]));
@@ -1136,7 +1176,7 @@ static int register_new_disk(int ctlr)
 		goto mem_msg;
 	
 	return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, 
-			sizeof(ReportLunData_struct), 0, 0, 0 );
+			sizeof(ReportLunData_struct), 0, 0, 0, TYPE_CMD);
 
 	if( return_code == IO_OK)
 	{
@@ -1290,126 +1330,25 @@ static int sendcmd(
 				      2: periph device address is scsi3addr */
 	unsigned int log_unit,
 	__u8	page_code,
-	unsigned char *scsi3addr)
+	unsigned char *scsi3addr,
+	int cmd_type)
 {
 	CommandList_struct *c;
 	int i;
 	unsigned long complete;
 	ctlr_info_t *info_p= hba[ctlr];
 	u64bit buff_dma_handle;
-	int status = IO_OK;
+	int status;
 
-	c = cmd_alloc(info_p, 1);
-	if (c == NULL)
-	{
+	if ((c = cmd_alloc(info_p, 1)) == NULL) {
 		printk(KERN_WARNING "cciss: unable to get memory");
 		return(IO_ERROR);
 	}
-	// Fill in Command Header 
-	c->Header.ReplyQueue = 0;  // unused in simple mode
-	if( buff != NULL) 	// buffer to fill 
-	{
-		c->Header.SGList = 1;
-		c->Header.SGTotal= 1;
-	} else	// no buffers to fill  
-	{
-		c->Header.SGList = 0;
-                c->Header.SGTotal= 0;
-	}
-	c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
-	// Fill in Request block 	
-	switch(cmd)
-	{
-		case  CISS_INQUIRY:
-			/* If the logical unit number is 0 then, this is going
-				to controller so It's a physical command
-				mode = 0 target = 0.
-				So we have nothing to write. 
-				otherwise, if use_unit_num == 1, 
-				mode = 1(volume set addressing) target = LUNID
-				otherwise, if use_unit_num == 2,
-				mode = 0(periph dev addr) target = scsi3addr 
-			*/
-			if(use_unit_num == 1)
-			{
-				c->Header.LUN.LogDev.VolId=
-                                	hba[ctlr]->drv[log_unit].LunID;
-                        	c->Header.LUN.LogDev.Mode = 1;
-			}
-			else if (use_unit_num == 2)
-			{
-				memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
-                        	c->Header.LUN.LogDev.Mode = 0; // phys dev addr 
-			}
-
-			/* are we trying to read a vital product page */
-			if(page_code != 0)
-			{
-				c->Request.CDB[1] = 0x01;
-				c->Request.CDB[2] = page_code;
-			}
-			c->Request.CDBLen = 6;
-			c->Request.Type.Type =  TYPE_CMD; // It is a command. 
-			c->Request.Type.Attribute = ATTR_SIMPLE;  
-			c->Request.Type.Direction = XFER_READ; // Read 
-			c->Request.Timeout = 0; // Don't time out 
-			c->Request.CDB[0] =  CISS_INQUIRY;
-			c->Request.CDB[4] = size  & 0xFF;  
-		break;
-		case CISS_REPORT_LOG:
-		case CISS_REPORT_PHYS:
-                        /* Talking to controller so It's a physical command
-                                mode = 00 target = 0.
-                                So we have nothing to write.
-                        */
-                        c->Request.CDBLen = 12;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
-                        c->Request.Type.Attribute = ATTR_SIMPLE; 
-                        c->Request.Type.Direction = XFER_READ; // Read
-                        c->Request.Timeout = 0; // Don't time out
-                        c->Request.CDB[0] = cmd;
-                        c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
-                        c->Request.CDB[7] = (size >> 16) & 0xFF;
-                        c->Request.CDB[8] = (size >> 8) & 0xFF;
-                        c->Request.CDB[9] = size & 0xFF;
-                break;
-
-		case CCISS_READ_CAPACITY:
-			c->Header.LUN.LogDev.VolId= 
-				hba[ctlr]->drv[log_unit].LunID;
-			c->Header.LUN.LogDev.Mode = 1;
-			c->Request.CDBLen = 10;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
-                        c->Request.Type.Attribute = ATTR_SIMPLE; 
-                        c->Request.Type.Direction = XFER_READ; // Read
-                        c->Request.Timeout = 0; // Don't time out
-                        c->Request.CDB[0] = CCISS_READ_CAPACITY;
-		break;
-		case CCISS_CACHE_FLUSH:
-			c->Request.CDBLen = 12;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
-                        c->Request.Type.Attribute = ATTR_SIMPLE;
-                        c->Request.Type.Direction = XFER_WRITE; // No data
-                        c->Request.Timeout = 0; // Don't time out
-                        c->Request.CDB[0] = BMIC_WRITE;  // BMIC Passthru
-                        c->Request.CDB[6] = BMIC_CACHE_FLUSH;
-		break;
-		default:
-			printk(KERN_WARNING
-				"cciss:  Unknown Command 0x%c sent attempted\n",
-				  cmd);
-			cmd_free(info_p, c, 1);
-			return(IO_ERROR);
-	};
-	// Fill in the scatter gather information
-	if (size > 0 ) 
-	{
-		buff_dma_handle.val = (__u64) pci_map_single( info_p->pdev, 
-			buff, size, PCI_DMA_BIDIRECTIONAL);
-		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
-		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
-		c->SG[0].Len = size;
-		c->SG[0].Ext = 0;  // we are not chaining
+	status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
+		log_unit, page_code, scsi3addr, cmd_type);
+	if (status != IO_OK) {
+		cmd_free(info_p, c, 1);
+		return status;
 	}
 resend_cmd1:
 	/*
@@ -2187,7 +2126,7 @@ static void cciss_getgeometry(int cntl_n
         }
 	/* Get the firmware version */ 
 	return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, 
-		sizeof(InquiryData_struct), 0, 0 ,0, NULL );
+		sizeof(InquiryData_struct), 0, 0 ,0, NULL, TYPE_CMD);
 	if (return_code == IO_OK)
 	{
 		hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
@@ -2201,7 +2140,7 @@ static void cciss_getgeometry(int cntl_n
 	}
 	/* Get the number of logical volumes */ 
 	return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, 
-			sizeof(ReportLunData_struct), 0, 0, 0, NULL );
+			sizeof(ReportLunData_struct), 0, 0, 0, NULL, TYPE_CMD);
 
 	if( return_code == IO_OK)
 	{
@@ -2475,7 +2414,8 @@ static void __devexit cciss_remove_one (
 	/* sendcmd will turn off interrupt, and send the flush...
 	* To write all data in the battery backed cache to disks */
 	memset(flush_buf, 0, 4);
-	return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL);
+	return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL,
+				TYPE_CMD);
 	if(return_code != IO_OK)
 	{
 		printk(KERN_WARNING "Error Flushing cache on controller %d\n", 
--- linux-2.5.63/drivers/block/cciss_scsi.c~sendcmd_cleanup	2003-02-27 13:11:23.000000000 +0600
+++ linux-2.5.63-scameron/drivers/block/cciss_scsi.c	2003-02-27 13:11:23.000000000 +0600
@@ -47,7 +47,8 @@ static int sendcmd(
 				      2: address is in scsi3addr */
 	unsigned int log_unit,
 	__u8	page_code,
-	unsigned char *scsi3addr );
+	unsigned char *scsi3addr,
+	int cmd_type);
 
 
 int __init cciss_scsi_detect(Scsi_Host_Template *tpnt);

_



^ permalink raw reply	[flat|nested] 5+ messages in thread
* Re: [PATCH] 2.5.63 cciss fix unlikely startup problem
@ 2003-02-27  7:30 Stephen Cameron
  0 siblings, 0 replies; 5+ messages in thread
From: Stephen Cameron @ 2003-02-27  7:30 UTC (permalink / raw)
  To: linux-kernel

Another cciss patch:

Make cciss driver retry 3rd party bus reset aborted commands up to 3 times.
(ported to 2.5 by me, original patch by Charles White)

This is needed for a multi port storage box that can have
multiple hosts connected to it, or be used in a multipath
configuration.  In certain configurations SCSI bus resets 
initiated by one host may affect another host.

-- steve


--- linux-2.5.63/drivers/block/cciss.c~retry_aborted	2003-02-27 13:11:18.000000000 +0600
+++ linux-2.5.63-scameron/drivers/block/cciss.c	2003-02-27 13:11:18.000000000 +0600
@@ -102,6 +102,9 @@ static struct board_type products[] = {
 #define MAX_CONFIG_WAIT 30000 
 #define MAX_IOCTL_CONFIG_WAIT 1000
 
+/*define how many times we will try a command because of bus resets */
+#define MAX_CMD_RETRIES 3
+
 #define READ_AHEAD 	 128
 #define NR_CMDS		 384 /* #commands that can be outstanding */
 #define MAX_CTLR 8
@@ -934,6 +937,7 @@ static int sendcmd_withirq(__u8	cmd,
 		c->SG[0].Len = size;
 		c->SG[0].Ext = 0;  // we are not chaining
 	}
+resend_cmd2:
 	c->waiting = &wait;
 	
 	/* Put the request on the tail of the queue and send it */
@@ -945,10 +949,6 @@ static int sendcmd_withirq(__u8	cmd,
 	
 	wait_for_completion(&wait);
 
-	/* unlock the buffers from DMA */
-        pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
-                	size, PCI_DMA_BIDIRECTIONAL);
-
 	if(c->err_info->CommandStatus != 0) 
 	{ /* an error has occurred */ 
 		switch(c->err_info->CommandStatus)
@@ -1000,11 +1000,22 @@ case CMD_HARDWARE_ERR:
 				return_status = IO_ERROR;
 			break;
 			case CMD_UNSOLICITED_ABORT:
-				printk(KERN_WARNING "cciss: cmd %p aborted "
-					"do to an unsolicited abort\n", c);
+				printk(KERN_WARNING 
+					"cciss%d: unsolicited abort %p\n",
+					ctlr, c);
+				if (c->retry_count < MAX_CMD_RETRIES) {
+					printk(KERN_WARNING 
+						"cciss%d: retrying %p\n", 
+						ctlr, c);
+					c->retry_count++;
+					/* erase the old error information */
+					memset(c->err_info, 0,
+						sizeof(ErrorInfo_struct));
+					return_status = IO_OK;
+					INIT_COMPLETION(wait);
+					goto resend_cmd2;
+				}
 				return_status = IO_ERROR;
-
-
 			break;
 			default:
 				printk(KERN_WARNING "cciss: cmd %p returned "
@@ -1013,6 +1024,9 @@ case CMD_HARDWARE_ERR:
 				return_status = IO_ERROR;
 		}
 	}	
+	/* unlock the buffers from DMA */
+	pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
+			size, PCI_DMA_BIDIRECTIONAL);
 	cmd_free(h, c, 0);
         return(return_status);
 
@@ -1283,6 +1297,7 @@ static int sendcmd(
 	unsigned long complete;
 	ctlr_info_t *info_p= hba[ctlr];
 	u64bit buff_dma_handle;
+	int status = IO_OK;
 
 	c = cmd_alloc(info_p, 1);
 	if (c == NULL)
@@ -1396,6 +1411,7 @@ static int sendcmd(
 		c->SG[0].Len = size;
 		c->SG[0].Ext = 0;  // we are not chaining
 	}
+resend_cmd1:
 	/*
          * Disable interrupt
          */
@@ -1428,9 +1444,6 @@ static int sendcmd(
 	printk(KERN_DEBUG "cciss: command completed\n");
 #endif /* CCISS_DEBUG */
 
-	/* unlock the data buffer from DMA */
-	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
-                                size, PCI_DMA_BIDIRECTIONAL);
 	if (complete != 1) {
 		if ( (complete & CISS_ERROR_BIT)
 		     && (complete & ~CISS_ERROR_BIT) == c->busaddr)
@@ -1448,8 +1461,30 @@ static int sendcmd(
 			 	))
 			{
 				complete = c->busaddr;
-			} else
-			{
+			} else {
+				if (c->err_info->CommandStatus ==
+						CMD_UNSOLICITED_ABORT) {
+					printk(KERN_WARNING "cciss%d: "
+						"unsolicited abort %p\n",
+						ctlr, c);
+					if (c->retry_count < MAX_CMD_RETRIES) {
+						printk(KERN_WARNING
+						   "cciss%d: retrying %p\n",
+						   ctlr, c);
+						c->retry_count++;
+						/* erase the old error */
+						/* information */
+						memset(c->err_info, 0,
+						   sizeof(ErrorInfo_struct));
+						goto resend_cmd1;
+					} else {
+						printk(KERN_WARNING
+						   "cciss%d: retried %p too "
+						   "many times\n", ctlr, c);
+						status = IO_ERROR;
+						goto cleanup1;
+					}
+				}
 				printk(KERN_WARNING "ciss ciss%d: sendcmd"
 				" Error %x \n", ctlr, 
 					c->err_info->CommandStatus); 
@@ -1459,27 +1494,31 @@ static int sendcmd(
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_size,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_num,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
-				cmd_free(info_p,c, 1);
-				return(IO_ERROR);
+				status = IO_ERROR;
+				goto cleanup1;
 			}
 		}
                 if (complete != c->busaddr) {
                         printk( KERN_WARNING "cciss cciss%d: SendCmd "
                       "Invalid command list address returned! (%lx)\n",
                                 ctlr, complete);
-                        cmd_free(info_p, c, 1);
-                        return (IO_ERROR);
+			status = IO_ERROR;
+			goto cleanup1;
                 }
         } else {
                 printk( KERN_WARNING
                         "cciss cciss%d: SendCmd Timeout out, "
                         "No command list address returned!\n",
                         ctlr);
-                cmd_free(info_p, c, 1);
-                return (IO_ERROR);
+		status = IO_ERROR;
         }
+		
+cleanup1:	
+	/* unlock the data buffer from DMA */
+	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
+				size, PCI_DMA_BIDIRECTIONAL);
 	cmd_free(info_p, c, 1);
-        return (IO_OK);
+	return (status);
 } 
 /*
  * Map (physical) PCI mem into (virtual) kernel space
@@ -1563,27 +1602,35 @@ static inline void complete_buffers(stru
 	}
 
 } 
+/* Assumes that CCISS_LOCK(h->ctlr) is held. */
+/* Zeros out the error record and then resends the command back */
+/* to the controller */
+static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
+{
+	/* erase the old error information */
+	memset(c->err_info, 0, sizeof(ErrorInfo_struct));
+
+	/* add it to software queue and then send it to the controller */
+	addQ(&(h->reqQ),c);
+	h->Qdepth++;
+	if(h->Qdepth > h->maxQsinceinit)
+		h->maxQsinceinit = h->Qdepth;
+
+	start_io(h);
+}
 /* checks the status of the job and calls complete buffers to mark all 
  * buffers for the completed job. 
  */ 
-static inline void complete_command( CommandList_struct *cmd, int timeout)
+static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
+		int timeout)
 {
 	int status = 1;
 	int i;
+	int retry_cmd = 0;
 	u64bit temp64;
 		
 	if (timeout)
 		status = 0; 
-	/* unmap the DMA mapping for all the scatter gather elements */
-	for(i=0; i<cmd->Header.SGList; i++)
-	{
-		temp64.val32.lower = cmd->SG[i].Addr.lower;
-		temp64.val32.upper = cmd->SG[i].Addr.upper;
-		pci_unmap_page(hba[cmd->ctlr]->pdev,
-			temp64.val, cmd->SG[i].Len, 
-			(cmd->Request.Type.Direction == XFER_READ) ? 
-				PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-	}
 
 	if(cmd->err_info->CommandStatus != 0) 
 	{ /* an error has occurred */ 
@@ -1657,8 +1704,18 @@ static inline void complete_command( Com
 				status=0;
 			break;
 			case CMD_UNSOLICITED_ABORT:
-				printk(KERN_WARNING "cciss: cmd %p aborted "
-					"do to an unsolicited abort\n", cmd);
+				printk(KERN_WARNING "cciss%d: unsolicited "
+					"abort %p\n", h->ctlr, cmd);
+				if (cmd->retry_count < MAX_CMD_RETRIES) {
+					retry_cmd=1;
+					printk(KERN_WARNING
+						"cciss%d: retrying %p\n",
+						h->ctlr, cmd);
+					cmd->retry_count++;
+				} else
+					printk(KERN_WARNING
+						"cciss%d: %p retried too "
+						"many times\n", h->ctlr, cmd);
 				status=0;
 			break;
 			case CMD_TIMEOUT:
@@ -1673,7 +1730,21 @@ static inline void complete_command( Com
 				status=0;
 		}
 	}
-
+	/* We need to return this command */
+	if(retry_cmd) {
+		resend_cciss_cmd(h,cmd);
+		return;
+	}	
+	/* command did not need to be retried */
+	/* unmap the DMA mapping for all the scatter gather elements */
+	for(i=0; i<cmd->Header.SGList; i++) {
+		temp64.val32.lower = cmd->SG[i].Addr.lower;
+		temp64.val32.upper = cmd->SG[i].Addr.upper;
+		pci_unmap_page(hba[cmd->ctlr]->pdev,
+			temp64.val, cmd->SG[i].Len,
+			(cmd->Request.Type.Direction == XFER_READ) ?
+				PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+	}
 	complete_buffers(cmd->rq->bio, status);
 
 #ifdef CCISS_DEBUG
@@ -1681,6 +1752,7 @@ static inline void complete_command( Com
 #endif /* CCISS_DEBUG */ 
 
 	end_that_request_last(cmd->rq);
+	cmd_free(h,cmd,1);
 }
 
 /* 
@@ -1827,8 +1899,7 @@ static void do_cciss_intr(int irq, void 
 			 if (c->busaddr == a) {
 				removeQ(&h->cmpQ, c);
 				if (c->cmd_type == CMD_RWREQ) {
-					complete_command(c, 0);
-					cmd_free(h, c, 1);
+					complete_command(h, c, 0);
 				} else if (c->cmd_type == CMD_IOCTL_PEND) {
 					complete(c->waiting);
 				}
--- linux-2.5.63/drivers/block/cciss_cmd.h~retry_aborted	2003-02-27 13:11:18.000000000 +0600
+++ linux-2.5.63-scameron/drivers/block/cciss_cmd.h	2003-02-27 13:11:18.000000000 +0600
@@ -240,6 +240,7 @@ typedef struct _CommandList_struct {
   struct _CommandList_struct *next;
   struct request *	   rq;
   struct completion *waiting;
+  int	 retry_count;
 #ifdef CONFIG_CISS_SCSI_TAPE
   void * scsi_cmd;
 #endif

_

^ permalink raw reply	[flat|nested] 5+ messages in thread
* [PATCH] 2.5.63 cciss fix unlikely startup problem
@ 2003-02-27  7:23 Stephen Cameron
  0 siblings, 0 replies; 5+ messages in thread
From: Stephen Cameron @ 2003-02-27  7:23 UTC (permalink / raw)
  To: linux-kernel

Applies to 2.5.63

* Make cciss driver wait longer for board to enter simple mode to
  handle an unlikely corner case.  (Hot replace of failed 144GB
  drive in RAID 5 set at just the wrong time prior to driver loading
  can make the board take a longer than usual time to go into "simple
  mode".  Without the patch, the driver gives up too early, and consequently
  doesn't work.  (A reboot will generally "fix" it.)  This patch avoids
  the problem.
* Fix a couple ioctls to return EAGAIN instead of inappropriate EFAULT.
-- steve

--- linux-2.5.63/drivers/block/cciss.c~cciss_cfg_table_wait_for_RHAS21	2003-02-26 11:07:55.000000000 +0600
+++ linux-2.5.63-scameron/drivers/block/cciss.c	2003-02-27 13:11:12.000000000 +0600
@@ -99,7 +99,8 @@ static struct board_type products[] = {
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
-#define MAX_CONFIG_WAIT 1000 
+#define MAX_CONFIG_WAIT 30000 
+#define MAX_IOCTL_CONFIG_WAIT 1000
 
 #define READ_AHEAD 	 128
 #define NR_CMDS		 384 /* #commands that can be outstanding */
@@ -479,8 +480,7 @@ static int cciss_ioctl(struct inode *ino
                         &(c->cfgtable->HostWrite.CoalIntCount));
 		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-		for(i=0;i<MAX_CONFIG_WAIT;i++)
-		{
+		for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {
 			if (!(readl(c->vaddr + SA5_DOORBELL) 
 					& CFGTBL_ChangeReq))
 				break;
@@ -488,8 +488,8 @@ static int cciss_ioctl(struct inode *ino
 			udelay(1000);
 		}	
 		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-		if (i >= MAX_CONFIG_WAIT)
-			return( -EFAULT);
+		if (i >= MAX_IOCTL_CONFIG_WAIT)
+			return -EAGAIN;
                 return(0);
         }
 	case CCISS_GETNODENAME:
@@ -526,8 +526,7 @@ static int cciss_ioctl(struct inode *ino
 			
 		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-		for(i=0;i<MAX_CONFIG_WAIT;i++)
-		{
+		for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {
 			if (!(readl(c->vaddr + SA5_DOORBELL) 
 					& CFGTBL_ChangeReq))
 				break;
@@ -535,8 +534,8 @@ static int cciss_ioctl(struct inode *ino
 			udelay(1000);
 		}	
 		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-		if (i >= MAX_CONFIG_WAIT)
-			return( -EFAULT);
+		if (i >= MAX_IOCTL_CONFIG_WAIT)
+			return -EAGAIN;
                 return(0);
         }
 
@@ -2050,12 +2049,15 @@ static int cciss_pci_init(ctlr_info_t *c
 		&(c->cfgtable->HostWrite.TransportRequest));
 	writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-	for(i=0;i<MAX_CONFIG_WAIT;i++)
-	{
+	/* under certain very rare conditions, this can take awhile.
+	 * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
+	 * as we enter this code.) */
+	for(i=0;i<MAX_CONFIG_WAIT;i++) {
 		if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
 			break;
 		/* delay and try again */
-		udelay(1000);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(10);
 	}	
 
 #ifdef CCISS_DEBUG

_

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2003-02-27 20:28 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-02-27  8:39 [PATCH] 2.5.63 cciss fix unlikely startup problem Stephen Cameron
  -- strict thread matches above, loose matches on Subject: below --
2003-02-27  8:36 Stephen Cameron
2003-02-27  8:24 Stephen Cameron
2003-02-27  7:30 Stephen Cameron
2003-02-27  7:23 Stephen Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®