patch-2.4.23 linux-2.4.23/drivers/scsi/aacraid/commctrl.c

Next file: linux-2.4.23/drivers/scsi/aacraid/comminit.c
Previous file: linux-2.4.23/drivers/scsi/aacraid/aacraid.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/drivers/scsi/aacraid/commctrl.c linux-2.4.23/drivers/scsi/aacraid/commctrl.c
@@ -362,7 +362,7 @@
  *	@dev: adapter
  *	@arg: ioctl arguments
  *
- *	This routine returns the firmware version.
+ *	This routine returns the driver version.
  *      Under Linux, there have been no version incompatibilities, so this is simple!
  */
 
@@ -371,14 +371,223 @@
 	struct revision response;
 
 	response.compat = 1;
-	response.version = dev->adapter_info.kernelrev;
-	response.build = dev->adapter_info.kernelbuild;
+	response.version = AAC_DRIVER_VERSION;
+	response.build = 9999;
 
 	if (copy_to_user(arg, &response, sizeof(response)))
 		return -EFAULT;
 	return 0;
 }
 
+/**
+ *
+ * aac_send_raw_scb
+ *
+ */
+
+int aac_send_raw_srb(struct aac_dev* dev, void* arg)
+{
+	struct fib* srbfib;
+	int status;
+	struct aac_srb *srbcmd;
+	struct aac_srb *user_srb = arg;
+	struct aac_srb_reply* user_reply;
+	struct aac_srb_reply* reply;
+	u32 fibsize = 0;
+	u32 flags = 0;
+	s32 rcode = 0;
+	u32 data_dir;
+	ulong sg_user[32];
+	ulong sg_list[32];
+	u32   sg_indx = 0;
+	u32 byte_count = 0;
+	u32 actual_fibsize = 0;
+	int i;
+
+
+	if (!capable(CAP_SYS_ADMIN)){
+		printk(KERN_DEBUG"aacraid: No permission to send raw srb\n"); 
+		return -EPERM;
+	}
+	/*
+	 *	Allocate and initialize a Fib then setup a BlockWrite command
+	 */
+	if (!(srbfib = fib_alloc(dev))) {
+		return -1;
+	}
+	fib_init(srbfib);
+
+	srbcmd = (struct aac_srb*) fib_data(srbfib);
+
+	if(copy_from_user((void*)&fibsize, (void*)&user_srb->count,sizeof(u32))){
+		printk(KERN_DEBUG"aacraid: Could not copy data size from user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+	if(copy_from_user(srbcmd, user_srb,fibsize)){
+		printk(KERN_DEBUG"aacraid: Could not copy srb from user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+	user_reply = arg+fibsize;
+
+	flags = srbcmd->flags;
+	// Fix up srb for endian and force some values
+	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);	// Force this
+	srbcmd->channel  = cpu_to_le32(srbcmd->channel);
+	srbcmd->target   = cpu_to_le32(srbcmd->target);
+	srbcmd->lun      = cpu_to_le32(srbcmd->lun);
+	srbcmd->flags    = cpu_to_le32(srbcmd->flags);
+	srbcmd->timeout  = cpu_to_le32(srbcmd->timeout);
+	srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
+	srbcmd->cdb_size = cpu_to_le32(srbcmd->cdb_size);
+
+	switch(srbcmd->flags & (SRB_DataIn | SRB_DataOut)){
+	case SRB_DataOut:
+		data_dir = SCSI_DATA_WRITE;
+		break;
+	case (SRB_DataIn | SRB_DataOut):
+		data_dir = SCSI_DATA_UNKNOWN;  
+		break;
+	case SRB_DataIn:
+		data_dir = SCSI_DATA_READ;
+		break;
+	default:
+		data_dir = SCSI_DATA_NONE;
+	}
+	
+	if( dev->pae_support ==1 ) {
+		struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
+		byte_count = 0;
+
+		// This should also catch if user used the 32 bit sgmap
+		actual_fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry64));
+		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
+			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+		if ((data_dir == SCSI_DATA_NONE) && psg->count) { // Dogs and cats sleeping with eachother - should not continue
+			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+
+		for (i = 0; i < psg->count; i++) {
+			dma_addr_t addr; 
+			u64 le_addr;
+			void* p;
+			p = kmalloc(psg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+			if(p == 0) {
+				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+				psg->sg[i].count,i,psg->count);
+				rcode = -ENOMEM;
+				goto cleanup;
+			}
+			sg_user[i] = (ulong)psg->sg[i].addr;
+			sg_list[i] = (ulong)p; // save so we can clean up later
+			sg_indx = i + 1;
+
+			if( flags & SRB_DataOut ){
+				if(copy_from_user(p,psg->sg[i].addr,psg->sg[i].count)){
+					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
+					rcode = -EFAULT;
+					goto cleanup;
+				}
+			}
+			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, scsi_to_pci_dma_dir(data_dir));
+
+			le_addr = cpu_to_le64(addr);
+			psg->sg[i].addr[1] = (u32)(le_addr>>32);
+			psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff);
+			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
+			byte_count += psg->sg[i].count;
+		}
+
+		srbcmd->count = cpu_to_le32(byte_count);
+		status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,0,0);
+	} else {
+		struct sgmap* psg = &srbcmd->sg;
+		byte_count = 0;
+
+		actual_fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
+		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
+			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+		if ((data_dir == SCSI_DATA_NONE) && psg->count) { // Dogs and cats sleeping with eachother - should not continue
+			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+		for (i = 0; i < psg->count; i++) {
+			dma_addr_t addr; 
+			void* p;
+			p = kmalloc(psg->sg[i].count,GFP_KERNEL);
+			if(p == 0) {
+				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+				psg->sg[i].count,i,psg->count);
+				rcode = -ENOMEM;
+				goto cleanup;
+			}
+			sg_user[i] = (ulong)(psg->sg[i].addr);
+			sg_list[i] = (ulong)p; // save so we can clean up later
+			sg_indx = i + 1;
+
+			if( flags & SRB_DataOut ){
+				if(copy_from_user((void*)p,(void*)(ulong)(psg->sg[i].addr),psg->sg[i].count)){
+					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
+					rcode = -EFAULT;
+					goto cleanup;
+				}
+			}
+			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, scsi_to_pci_dma_dir(data_dir));
+
+			psg->sg[i].addr = cpu_to_le32(addr);
+			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
+			byte_count += psg->sg[i].count;
+		}
+		srbcmd->count = cpu_to_le32(byte_count);
+		status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, 0, 0);
+	}
+
+	if (status != 0){
+		printk(KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"); 
+		rcode = -1;
+		goto cleanup;
+	}
+
+	if( flags & SRB_DataIn ) {
+		for(i = 0 ; i < sg_indx; i++){
+			if(copy_to_user((void*)(sg_user[i]),(void*)(sg_list[i]),le32_to_cpu(srbcmd->sg.sg[i].count))){
+				printk(KERN_DEBUG"aacraid: Could not copy sg data to user\n"); 
+				rcode = -EFAULT;
+				goto cleanup;
+
+			}
+		}
+	}
+
+	reply = (struct aac_srb_reply *) fib_data(srbfib);
+	if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
+		printk(KERN_DEBUG"aacraid: Could not copy reply to user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+cleanup:
+	for(i=0; i < sg_indx; i++){
+		kfree((void*)sg_list[i]);
+	}
+	fib_complete(srbfib);
+	fib_free(srbfib);
+
+	return rcode;
+}
+
 
 struct aac_pci_info {
         u32 bus;
@@ -427,6 +636,9 @@
 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
 		status = close_getadapter_fib(dev, arg);
 		break;
+	case FSACTL_SEND_RAW_SRB:
+		status = aac_send_raw_srb(dev,arg);
+		break;
 	case FSACTL_GET_PCI_INFO:
 		status = aac_get_pci_info(dev,arg);
 		break;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)