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
- Lines: 245
- Date:
2003-11-28 10:26:20.000000000 -0800
- Orig file:
linux-2.4.22/drivers/scsi/aacraid/commctrl.c
- Orig date:
2003-08-25 04:44:42.000000000 -0700
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)