cciss.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,278 行 · 第 1/5 页
C
2,278 行
/* Copy the error information out */ iocommand.error_info = *(c->err_info); if ( copy_to_user(argp, &iocommand, sizeof( IOCTL_Command_struct) ) ) { kfree(buff); cmd_free(host, c, 0); return( -EFAULT); } if (iocommand.Request.Type.Direction == XFER_READ) { /* Copy the data out of the buffer we created */ if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) { kfree(buff); cmd_free(host, c, 0); return -EFAULT; } } kfree(buff); cmd_free(host, c, 0); return(0); } case CCISS_BIG_PASSTHRU: { BIG_IOCTL_Command_struct *ioc; 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 __user *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, argp, sizeof(*ioc))) { status = -EFAULT; goto cleanup1; } if ((ioc->buf_size < 1) && (ioc->Request.Type.Direction != XFER_NONE)) { status = -EINVAL; goto cleanup1; } /* Check kmalloc limits using all SGs */ if (ioc->malloc_size > MAX_KMALLOC_SIZE) { status = -EINVAL; goto cleanup1; } if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) { status = -EINVAL; goto cleanup1; } 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 = 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; } else { memset(buff[sg_used], 0, sz); } left -= sz; data_ptr += sz; sg_used++; } if ((c = cmd_alloc(host , 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( host->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(&host->reqQ, c); host->Qdepth++; start_io(host); 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( host->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(argp, ioc, sizeof(*ioc))) { cmd_free(host, c, 0); status = -EFAULT; goto cleanup1; } if (ioc->Request.Type.Direction == XFER_READ) { /* Copy the data out of the buffer we created */ BYTE __user *ptr = ioc->buf; for(i=0; i< sg_used; i++) { if (copy_to_user(ptr, buff[i], buff_size[i])) { cmd_free(host, c, 0); status = -EFAULT; goto cleanup1; } ptr += buff_size[i]; } } cmd_free(host, 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; } }static int cciss_revalidate(struct gendisk *disk){ drive_info_struct *drv = disk->private_data; set_capacity(disk, drv->nr_blocks); return 0;}/* * revalidate_allvol is for online array config utilities. After a * utility reconfigures the drives in the array, it can use this function * (through an ioctl) to make the driver zap any previous disk structs for * that controller and get new ones. * * Right now I'm using the getgeometry() function to do this, but this * function should probably be finer grained and allow you to revalidate one * particualar logical volume (instead of all of them on a particular * controller). */static int revalidate_allvol(ctlr_info_t *host){ int ctlr = host->ctlr, i; unsigned long flags; spin_lock_irqsave(CCISS_LOCK(ctlr), flags); if (host->usage_count > 1) { spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); printk(KERN_WARNING "cciss: Device busy for volume" " revalidation (usage=%d)\n", host->usage_count); return -EBUSY; } host->usage_count++; spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); for(i=0; i< NWD; i++) { struct gendisk *disk = host->gendisk[i]; if (disk->flags & GENHD_FL_UP) del_gendisk(disk); } /* * Set the partition and block size structures for all volumes * on this controller to zero. We will reread all of this data */ memset(host->drv, 0, sizeof(drive_info_struct) * CISS_MAX_LUN); /* * Tell the array controller not to give us any interrupts while * we check the new geometry. Then turn interrupts back on when * we're done. */ host->access.set_intr_mask(host, CCISS_INTR_OFF); cciss_getgeometry(ctlr); host->access.set_intr_mask(host, CCISS_INTR_ON); /* Loop through each real device */ for (i = 0; i < NWD; i++) { struct gendisk *disk = host->gendisk[i]; drive_info_struct *drv = &(host->drv[i]); if (!drv->nr_blocks) continue; blk_queue_hardsect_size(host->queue, drv->block_size); set_capacity(disk, drv->nr_blocks); add_disk(disk); } host->usage_count--; return 0;}static int deregister_disk(struct gendisk *disk){ unsigned long flags; ctlr_info_t *h = get_host(disk); drive_info_struct *drv = get_drv(disk); int ctlr = h->ctlr; if (!capable(CAP_SYS_RAWIO)) return -EPERM; spin_lock_irqsave(CCISS_LOCK(ctlr), flags); /* make sure logical volume is NOT is use */ if( drv->usage_count > 1) { spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); return -EBUSY; } drv->usage_count++; spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); /* invalidate the devices and deregister the disk */ if (disk->flags & GENHD_FL_UP) del_gendisk(disk); /* check to see if it was the last disk */ if (drv == h->drv + h->highest_lun) { /* if so, find the new hightest lun */ int i, newhighest =-1; for(i=0; i<h->highest_lun; i++) { /* if the disk has size > 0, it is available */ if (h->drv[i].nr_blocks) newhighest = i; } h->highest_lun = newhighest; } --h->num_luns; /* zero out the disk size info */ drv->nr_blocks = 0; drv->block_size = 0; drv->cylinders = 0; drv->LunID = 0; return(0);}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]; u64bit buff_dma_handle; int status = IO_OK; c->cmd_type = CMD_IOCTL_PEND; c->Header.ReplyQueue = 0; if( buff != NULL) { c->Header.SGList = 1; c->Header.SGTotal= 1; } else { c->Header.SGList = 0; c->Header.SGTotal= 0; } 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, 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= 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; } /* 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.Attribute = ATTR_SIMPLE; 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_PHYS: /* Talking to controller so It's a physical command mode = 00 target = 0. Nothing to write. */ 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.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%d: Unknown Command 0x%c\n", ctlr, cmd); return(IO_ERROR); } } 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 */ } 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; /* Put the request on the tail of the queue and send it */ 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); if(c->err_info->CommandStatus != 0) { /* an error has occurred */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?