patch-2.4.21 linux-2.4.21/drivers/block/cpqarray.c
Next file: linux-2.4.21/drivers/block/elevator.c
Previous file: linux-2.4.21/drivers/block/cciss_scsi.h
Back to the patch index
Back to the overall index
- Lines: 929
- Date:
2003-06-13 07:51:32.000000000 -0700
- Orig file:
linux-2.4.20/drivers/block/cpqarray.c
- Orig date:
2002-11-28 15:53:12.000000000 -0800
diff -urN linux-2.4.20/drivers/block/cpqarray.c linux-2.4.21/drivers/block/cpqarray.c
@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Questions/Comments/Bugfixes to arrays@compaq.com
+ * Questions/Comments/Bugfixes to Cpqarray-discuss@lists.sourceforge.net
*
*/
#include <linux/config.h> /* CONFIG_PROC_FS */
@@ -41,13 +41,13 @@
#define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.21)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,21)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.25)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,25)
/* Embedded module documentation macros - see modules.h */
/* Original author Chris Frantz - Compaq Computer Corporation */
MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.21");
+MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.25");
MODULE_LICENSE("GPL");
#define MAJOR_NR COMPAQ_SMART2_MAJOR
@@ -162,6 +162,7 @@
static int ida_release(struct inode *inode, struct file *filep);
static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io);
+static int ida_ctlr_big_ioctl( int ctlr, int dsk, ida_big_ioctl_t *io);
static void do_ida_request(request_queue_t *q);
static void start_io(ctlr_info_t *h);
@@ -279,8 +280,7 @@
for(i=0; i<=h->highest_lun; i++) {
drv = &h->drv[i];
- if(drv->nr_blks != 0)
- {
+ if(drv->nr_blks != 0) {
size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
ctlr, i, drv->blk_size, drv->nr_blks);
pos += size; len += size;
@@ -293,7 +293,8 @@
c = h->reqQ;
size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
- if (c) c=c->next;
+ if (c)
+ c=c->next;
while(c && c != h->reqQ) {
size = sprintf(buffer+len, "->%p", c);
pos += size; len += size;
@@ -302,7 +303,8 @@
c = h->cmpQ;
size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
- if (c) c=c->next;
+ if (c)
+ c=c->next;
while(c && c != h->cmpQ) {
size = sprintf(buffer+len, "->%p", c);
pos += size; len += size;
@@ -352,12 +354,12 @@
ctlr_info_t *tmp_ptr;
char buff[4];
- if (pdev->driver_data == NULL)
+ tmp_ptr = pci_get_drvdata(pdev);
+ if (tmp_ptr == NULL)
{
printk( KERN_ERR "cpqarray: Unable to remove device \n");
return;
}
- tmp_ptr = (ctlr_info_t *) pdev->driver_data;
i = tmp_ptr->ctlr;
if (hba[i] == NULL)
{
@@ -369,13 +371,12 @@
/* sendcmd will turn off interrupt, and send the flush...
* To write all data in the battery backed cache to disks */
memset(buff, 0 , 4);
- if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
- {
+ if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0)) {
printk(KERN_WARNING "Unable to flush cache on controller %d\n",
i);
}
free_irq(hba[i]->intr, hba[i]);
- pdev->driver_data = NULL;
+ pci_set_drvdata(pdev, NULL);
/* remove it from the disk list */
del_gendisk(&(hba[i]->gendisk));
@@ -399,8 +400,7 @@
{
char buff[4];
- if (hba[i] == NULL)
- {
+ if (hba[i] == NULL) {
printk(KERN_ERR "cpqarray: device appears to "
"already be removed \n");
return;
@@ -409,8 +409,7 @@
/* sendcmd will turn off interrupt, and send the flush...
* To write all data in the battery backed cache to disks
* no data returned, but don't want to send NULL to sendcmd */
- if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
- {
+ if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0)) {
printk(KERN_WARNING "Unable to flush cache on controller %d\n",
i);
}
@@ -488,15 +487,14 @@
memset(hba[i], 0, sizeof(ctlr_info_t));
/* fill in default block size */
for(j=0;j<256;j++)
- hba[i]->hardsizes[j] = BLOCK_SIZE;
+ hba[i]->hardsizes[j] = hba[i]->drv[j].blk_size;
sprintf(hba[i]->devname, "ida%d", i);
hba[i]->ctlr = i;
/* Initialize the pdev driver private data */
- pdev->driver_data = hba[i];
+ pci_set_drvdata(pdev, hba[i]);
- if (cpqarray_pci_init(hba[i], pdev) != 0)
- {
+ if (cpqarray_pci_init(hba[i], pdev) != 0) {
release_io_mem(hba[i]);
free_hba(i);
return (-1);
@@ -510,8 +508,7 @@
/* If this successful it should insure that we are the only */
/* instance of the driver */
- if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops))
- {
+ if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
printk(KERN_ERR "cpqarray: Unable to get major number %d for ida\n",
MAJOR_NR+i);
release_io_mem(hba[i]);
@@ -522,8 +519,8 @@
hba[i]->access.set_intr_mask(hba[i], 0);
if (request_irq(hba[i]->intr, do_ida_intr,
- SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i]))
- {
+ SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
+ hba[i]->devname, hba[i])) {
printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n",
hba[i]->intr, hba[i]->devname);
@@ -538,8 +535,7 @@
hba[i]->cmd_pool_bits = (__u32*)kmalloc(
((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
- if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL)
- {
+ if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL) {
if(hba[i]->cmd_pool_bits)
kfree(hba[i]->cmd_pool_bits);
if(hba[i]->cmd_pool)
@@ -583,6 +579,7 @@
hba[i]->gendisk.part = hba[i]->hd;
hba[i]->gendisk.sizes = hba[i]->sizes;
hba[i]->gendisk.nr_real = hba[i]->highest_lun+1;
+ hba[i]->gendisk.fops = &ida_fops;
/* Get on the disk list */
add_gendisk(&(hba[i]->gendisk));
@@ -622,8 +619,7 @@
pci_register_driver(&cpqarray_pci_driver);
cpqarray_eisa_detect();
- for(i=0; i< MAX_CTLR; i++)
- {
+ for(i=0; i< MAX_CTLR; i++) {
if (hba[i] != NULL)
num_cntlrs_reg++;
}
@@ -634,13 +630,10 @@
static int alloc_cpqarray_hba(void)
{
int i;
- for(i=0; i< MAX_CTLR; i++)
- {
- if (hba[i] == NULL)
- {
+ for(i=0; i< MAX_CTLR; i++) {
+ if (hba[i] == NULL) {
hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
- if(hba[i]==NULL)
- {
+ if(hba[i]==NULL) {
printk(KERN_ERR "cpqarray: out of memory.\n");
return (-1);
}
@@ -674,8 +667,7 @@
pci_read_config_word(pdev, PCI_COMMAND, &command);
/* check to see if controller has been disabled */
- if(!(command & 0x02))
- {
+ if(!(command & 0x02)) {
printk(KERN_WARNING "cpqarray: controller appears to be disabled\n");
return(-1);
}
@@ -688,13 +680,11 @@
for(i=0; i<6; i++)
addr[i] = pci_resource_start(pdev, i);
- if (pci_enable_device(pdev))
- {
+ if (pci_enable_device(pdev)) {
printk(KERN_ERR "cpqarray: Unable to Enable PCI device\n");
return -1;
}
- if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0)
- {
+ if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0) {
printk(KERN_ERR "cpqarray: Unable to set DMA mask\n");
return -1;
}
@@ -719,18 +709,16 @@
);
c->intr = irq;
- for(i=0; i<6; i++)
- {
- if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)
- { /* IO space */
+ for(i=0; i<6; i++) {
+ if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) {
+ /* IO space */
c->io_mem_addr = addr[i];
c->io_mem_length = pci_resource_end(pdev, i)
- pci_resource_start(pdev, i) +1;
// printk("IO Value found addr[%d] %lx %lx\n",
// i, c->io_mem_addr, c->io_mem_length);
if(!request_region( c->io_mem_addr, c->io_mem_length,
- "cpqarray"))
- {
+ "cpqarray")) {
printk( KERN_WARNING "cpqarray I/O memory range already in use addr %lx length = %ld\n", c->io_mem_addr, c->io_mem_length);
c->io_mem_addr = 0;
c->io_mem_length = 0;
@@ -740,7 +728,8 @@
}
c->paddr = 0;
for(i=0; i<6; i++)
- if (!(pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)) {
+ if (!(pci_resource_flags(pdev, i) &
+ PCI_BASE_ADDRESS_SPACE_IO)) {
c->paddr = pci_resource_start (pdev, i);
break;
}
@@ -843,8 +832,7 @@
hba[ctlr]->io_mem_length = 0x7FF;
if(!request_region( hba[ctlr]->io_mem_addr,
hba[ctlr]->io_mem_length,
- "cpqarray"))
- {
+ "cpqarray")) {
printk( KERN_WARNING "cpqarray: I/0 range already in use addr = %lx length=%ld\n",
hba[ctlr]->io_mem_addr, hba[ctlr]->io_mem_length);
free_hba(ctlr);
@@ -854,10 +842,14 @@
* Read the config register to find our interrupt
*/
intr = inb(eisa[i]+0xCC0) >> 4;
- if (intr & 1) intr = 11;
- else if (intr & 2) intr = 10;
- else if (intr & 4) intr = 14;
- else if (intr & 8) intr = 15;
+ if (intr & 1)
+ intr = 11;
+ else if (intr & 2)
+ intr = 10;
+ else if (intr & 4)
+ intr = 14;
+ else if (intr & 8)
+ intr = 15;
hba[ctlr]->intr = intr;
sprintf(hba[ctlr]->devname, "ida%d", ctlr);
@@ -894,19 +886,18 @@
if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
return -ENXIO;
- if (!suser() && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0)
- return -ENXIO;
-
/*
* Root is allowed to open raw volume zero even if its not configured
* so array config can still work. I don't think I really like this,
* but I'm already using way to many device nodes to claim another one
* for "raw controller".
*/
- if (suser()
- && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0
- && MINOR(inode->i_rdev) != 0)
- return -ENXIO;
+ if (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) {
+ if (MINOR(inode->i_rdev) != 0)
+ return -ENXIO;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ }
hba[ctlr]->drv[dsk].usage_count++;
hba[ctlr]->usage_count++;
@@ -947,7 +938,8 @@
static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c)
{
if (c && c->next != c) {
- if (*Qptr == c) *Qptr = c->next;
+ if (*Qptr == c)
+ *Qptr = c->next;
c->prev->next = c->next;
c->next->prev = c->prev;
} else {
@@ -985,8 +977,7 @@
if (creq->nr_segments > SG_MAX)
BUG();
- if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR )
- {
+ if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) {
printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
h->ctlr, creq->rq_dev, creq);
blkdev_dequeue_request(creq);
@@ -1036,8 +1027,7 @@
bh = bh->b_reqnext;
}
/* Now do all the DMA Mappings */
- for( i=0; i < seg; i++)
- {
+ for( i=0; i < seg; i++) {
c->req.sg[i].size = tmp_sg[i].length;
c->req.sg[i].addr = (__u32) pci_map_page(
h->pci_dev, tmp_sg[i].page, tmp_sg[i].offset,
@@ -1131,7 +1121,8 @@
cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
ok = 0;
}
- if (timeout) ok = 0;
+ if (timeout)
+ ok = 0;
/* unmap the DMA mapping for all the scatter gather elements */
for(i=0; i<cmd->req.hdr.sg_cnt; i++)
{
@@ -1192,15 +1183,14 @@
* But rcode = 0.
*/
- if((a1 & 0x03) && (c->req.hdr.rcode == 0))
- {
+ if((a1 & 0x03) && (c->req.hdr.rcode == 0)) {
c->req.hdr.rcode = RCODE_INVREQ;
}
if (c->type == CMD_RWREQ) {
complete_command(c, 0);
cmd_free(h, c, 1);
} else if (c->type == CMD_IOCTL_PEND) {
- c->type = CMD_IOCTL_DONE;
+ complete(c->waiting);
}
continue;
}
@@ -1238,8 +1228,6 @@
int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
int error;
- ida_ioctl_t *io = (ida_ioctl_t*)arg;
- ida_ioctl_t my_io;
switch(cmd) {
case HDIO_GETGEO:
@@ -1286,26 +1274,50 @@
}
case IDAGETDRVINFO:
+ {
+
+ ida_ioctl_t *io = (ida_ioctl_t*)arg;
return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
- case BLKGETSIZE:
- if (!arg) return -EINVAL;
- return put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects,
- (unsigned long *)arg);
- case BLKGETSIZE64:
- return put_user((u64)(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects) << 9, (u64*)arg);
+ }
case BLKRRPART:
return revalidate_logvol(inode->i_rdev, 1);
case IDAPASSTHRU:
- if (!suser()) return -EPERM;
- error = copy_from_user(&my_io, io, sizeof(my_io));
- if (error) return error;
+ {
+
+ ida_ioctl_t *io = (ida_ioctl_t*)arg;
+ ida_ioctl_t my_io;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ if (copy_from_user(&my_io, io, sizeof(my_io)))
+ return -EFAULT;
error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
- if (error) return error;
- if(copy_to_user(io, &my_io, sizeof(my_io)))
+ if (error)
+ return error;
+ if (copy_to_user(io, &my_io, sizeof(my_io)))
return -EFAULT;
- return error;
+ return 0;
+ }
+ case IDABIGPASSTHRU:
+ {
+
+ ida_big_ioctl_t *io = (ida_big_ioctl_t*)arg;
+ ida_big_ioctl_t my_io;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ if (copy_from_user(&my_io, io, sizeof(my_io)))
+ return -EFAULT;
+ error = ida_ctlr_big_ioctl(ctlr, dsk, &my_io);
+ if (error)
+ return error;
+ if (copy_to_user(io, &my_io, sizeof(my_io)))
+ return -EFAULT;
+ return 0;
+ }
case IDAGETCTLRSIG:
- if (!arg) return -EINVAL;
+ if (!arg)
+ return -EINVAL;
put_user(hba[ctlr]->ctlr_sig, (int*)arg);
return 0;
case IDAREVALIDATEVOLS:
@@ -1319,7 +1331,8 @@
ida_pci_info_struct pciinfo;
- if (!arg) return -EINVAL;
+ if (!arg)
+ return -EINVAL;
pciinfo.bus = hba[ctlr]->pci_dev->bus->number;
pciinfo.dev_fn = hba[ctlr]->pci_dev->devfn;
pciinfo.board_id = hba[ctlr]->board_id;
@@ -1347,8 +1360,7 @@
/* count partitions 1 to 15 with sizes > 0 */
start = (dsk << NWD_SHIFT);
- for(i=1; i <IDA_MAX_PART; i++)
- {
+ for(i=1; i <IDA_MAX_PART; i++) {
int minor = start+i;
if(hba[ctlr]->sizes[minor] != 0)
num_parts++;
@@ -1360,6 +1372,8 @@
return(0);
}
+ case BLKGETSIZE:
+ case BLKGETSIZE64:
case BLKFLSBUF:
case BLKBSZSET:
case BLKBSZGET:
@@ -1394,6 +1408,7 @@
void *p = NULL;
unsigned long flags;
int error;
+ DECLARE_COMPLETION(wait);
if ((c = cmd_alloc(h, 0)) == NULL)
return -ENOMEM;
@@ -1411,8 +1426,7 @@
switch(io->cmd) {
case PASSTHRU_A:
p = kmalloc(io->sg[0].size, GFP_KERNEL);
- if (!p)
- {
+ if (!p) {
error = -ENOMEM;
cmd_free(h, c, 0);
return(error);
@@ -1431,11 +1445,11 @@
c->req.hdr.sg_cnt = 1;
break;
case IDA_READ:
+ case SENSE_SURF_STATUS:
case READ_FLASH_ROM:
case SENSE_CONTROLLER_PERFORMANCE:
p = kmalloc(io->sg[0].size, GFP_KERNEL);
- if (!p)
- {
+ if (!p) {
error = -ENOMEM;
cmd_free(h, c, 0);
return(error);
@@ -1452,8 +1466,7 @@
case COLLECT_BUFFER:
case WRITE_FLASH_ROM:
p = kmalloc(io->sg[0].size, GFP_KERNEL);
- if (!p)
- {
+ if (!p) {
error = -ENOMEM;
cmd_free(h, c, 0);
return(error);
@@ -1474,7 +1487,9 @@
c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);
c->req.hdr.sg_cnt = 1;
}
-
+
+ c->waiting = &wait;
+
/* Put the request on the tail of the request queue */
spin_lock_irqsave(&io_request_lock, flags);
addQ(&h->reqQ, c);
@@ -1483,8 +1498,7 @@
spin_unlock_irqrestore(&io_request_lock, flags);
/* Wait for completion */
- while(c->type != CMD_IOCTL_DONE)
- schedule();
+ wait_for_completion(&wait);
/* Unmap the DMA */
pci_unmap_single(h->pci_dev, c->req.sg[0].addr, c->req.sg[0].size,
@@ -1496,6 +1510,7 @@
sizeof(ida_ioctl_t),
PCI_DMA_BIDIRECTIONAL);
case IDA_READ:
+ case SENSE_SURF_STATUS:
case DIAG_PASS_THRU:
case SENSE_CONTROLLER_PERFORMANCE:
case READ_FLASH_ROM:
@@ -1520,6 +1535,175 @@
}
/*
+ * ida_ctlr_big_ioctl is for passing commands to the controller from userspace.
+ * The command block (io) has already been copied to kernel space for us,
+ *
+ * Only root may perform a controller passthru command, however I'm not doing
+ * any serious sanity checking on the arguments.
+ */
+static int ida_ctlr_big_ioctl(int ctlr, int dsk, ida_big_ioctl_t *io)
+{
+ ctlr_info_t *h = hba[ctlr];
+ cmdlist_t *c;
+ __u8 *scsi_param = NULL;
+ __u8 *buff[SG_MAX] = {NULL,};
+ size_t buff_size[SG_MAX];
+ __u8 sg_used = 0;
+ unsigned long flags;
+ int error = 0;
+ int i;
+ DECLARE_COMPLETION(wait);
+
+ /* Check kmalloc limits using all SGs */
+ if( io->buff_malloc_size > IDA_MAX_KMALLOC_SIZE)
+ return -EINVAL;
+ if( io->buff_size > io->buff_malloc_size * SG_MAX)
+ return -EINVAL;
+ if ((c = cmd_alloc(h, 0)) == NULL)
+ return -ENOMEM;
+
+ c->ctlr = ctlr;
+ c->hdr.unit = (io->unit & UNITVALID) ? (io->unit & ~UNITVALID) : dsk;
+ c->hdr.size = sizeof(rblk_t) >> 2;
+ c->size += sizeof(rblk_t);
+
+ c->req.hdr.cmd = io->cmd;
+ c->req.hdr.blk = io->blk;
+ c->req.hdr.blk_cnt = io->blk_cnt;
+ c->type = CMD_IOCTL_PEND;
+
+ /* Pre submit processing */
+ /* for passthru_a the scsi command is in another record */
+ if (io->cmd == PASSTHRU_A) {
+
+ if (io->scsi_param == NULL)
+ {
+ error = -EINVAL;
+ cmd_free(h, c, 0);
+ return(error);
+ }
+ scsi_param = kmalloc(sizeof(scsi_param_t), GFP_KERNEL);
+ if (scsi_param == NULL) {
+ error = -ENOMEM;
+ cmd_free(h, c, 0);
+ return(error);
+ }
+
+ /* copy the scsi command to get passed thru */
+ if (copy_from_user(scsi_param, io->scsi_param,
+ sizeof(scsi_param_t))) {
+ kfree(scsi_param);
+ cmd_free(h, c, 0);
+ return -EFAULT;
+ }
+
+ /* with this command the scsi command is seperate */
+ c->req.hdr.blk = pci_map_single(h->pci_dev, scsi_param,
+ sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+ }
+
+ /* fill in the SG entries */
+ /* create buffers if we need to */
+ if(io->buff_size > 0) {
+ size_t size_left_alloc = io->buff_size;
+ __u8 *data_ptr = io->buff;
+
+ while(size_left_alloc > 0) {
+ buff_size[sg_used] = (size_left_alloc
+ > io->buff_malloc_size)
+ ? io->buff_malloc_size : size_left_alloc;
+ buff[sg_used] = kmalloc( buff_size[sg_used],
+ GFP_KERNEL);
+ if (buff[sg_used] == NULL) {
+ error = -ENOMEM;
+ goto ida_alloc_cleanup;
+ }
+ if(io->xfer_type & IDA_XFER_WRITE) {
+ /* Copy the data into the buffer created */
+ if (copy_from_user(buff[sg_used], data_ptr,
+ buff_size[sg_used])) {
+ error = -EFAULT;
+ goto ida_alloc_cleanup;
+ }
+ }
+ /* put the data into the scatter gather list */
+ c->req.sg[sg_used].size = buff_size[sg_used];
+ c->req.sg[sg_used].addr = pci_map_single(h->pci_dev,
+ buff[sg_used], buff_size[sg_used],
+ PCI_DMA_BIDIRECTIONAL);
+
+ size_left_alloc -= buff_size[sg_used];
+ data_ptr += buff_size[sg_used];
+ sg_used++;
+ }
+ }
+ c->req.hdr.sg_cnt = sg_used;
+
+ c->waiting = &wait;
+
+ /* Put the request on the tail of the request queue */
+ spin_lock_irqsave(&io_request_lock, flags);
+ addQ(&h->reqQ, c);
+ h->Qdepth++;
+ start_io(h);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+
+ /* Wait for completion */
+ wait_for_completion(&wait);
+ /* Unmap the DMA */
+ for(i=0; i<c->req.hdr.sg_cnt; i++) {
+ pci_unmap_single(h->pci_dev, c->req.sg[i].addr,
+ c->req.sg[i].size, PCI_DMA_BIDIRECTIONAL);
+ }
+
+ /* if we are reading data from the hardware copy it back to user */
+ if (io->xfer_type & IDA_XFER_READ) {
+ __u8 *data_ptr = io->buff;
+ int i;
+
+ for(i=0; i<c->req.hdr.sg_cnt; i++) {
+ if (copy_to_user(data_ptr, buff[i], buff_size[i])) {
+ error = -EFAULT;
+ goto ida_alloc_cleanup;
+ }
+ data_ptr += buff_size[i];
+
+ }
+
+ }
+
+ io->rcode = c->req.hdr.rcode;
+
+ if(scsi_param) {
+ pci_unmap_single(h->pci_dev, c->req.hdr.blk,
+ sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+ /* copy the scsi_params back to the user */
+ if( copy_to_user(io->scsi_param, scsi_param,
+ sizeof(scsi_param_t))) {
+ error = -EFAULT;
+ }
+ kfree(scsi_param);
+ }
+ cmd_free(h, c, 0);
+ return(error);
+
+ida_alloc_cleanup:
+ if(scsi_param) {
+ pci_unmap_single(h->pci_dev, c->req.hdr.blk,
+ sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+ kfree(scsi_param);
+ }
+ for (i=0; i<sg_used; i++) {
+ if(buff[sg_used] != NULL) {
+ pci_unmap_single(h->pci_dev, c->req.sg[i].addr,
+ buff_size[sg_used], PCI_DMA_BIDIRECTIONAL);
+ kfree(buff[sg_used]);
+ }
+ }
+ cmd_free(h, c, 0);
+ return(error);
+}
+/*
* Commands are pre-allocated in a large block. Here we use a simple bitmap
* scheme to suballocte them to the driver. Operations that are not time
* critical (and can wait for kmalloc and possibly sleep) can pass in NULL
@@ -1720,7 +1904,7 @@
hba[ctlr]->gendisk.nr_real = 0;
for(i=0;i<256;i++)
- hba[ctlr]->hardsizes[i] = BLOCK_SIZE;
+ hba[ctlr]->hardsizes[i] = 0;
/*
* Tell the array controller not to give us any interrupts while
* we check the new geometry. Then turn interrupts back on when
@@ -1752,8 +1936,7 @@
spin_lock_irqsave(&io_request_lock, flags);
/* make sure logical volume is NOT is use */
- if( h->drv[logvol].usage_count > 1)
- {
+ if( h->drv[logvol].usage_count > 1) {
spin_unlock_irqrestore(&io_request_lock, flags);
return -EBUSY;
}
@@ -1763,21 +1946,21 @@
/* invalidate the devices and deregister the disk */
max_p = gdev->max_p;
start = logvol << gdev->minor_shift;
- for (i=max_p-1; i>=0; i--)
- {
+ for (i=max_p-1; i>=0; i--) {
int minor = start+i;
// printk("invalidating( %d %d)\n", ctlr, minor);
invalidate_device(MKDEV(MAJOR_NR+ctlr, minor), 1);
/* so open will now fail */
hba[ctlr]->sizes[minor] = 0;
+ /* so it will no longer appear in /proc/partitions */
+ gdev->part[minor].start_sect = 0;
+ gdev->part[minor].nr_sects = 0;
}
/* check to see if it was the last disk */
- if (logvol == h->highest_lun)
- {
+ if (logvol == h->highest_lun) {
/* if so, find the new hightest lun */
int i, newhighest =-1;
- for(i=0; i<h->highest_lun; i++)
- {
+ for(i=0; i<h->highest_lun; i++) {
/* if the disk has size > 0, it is available */
if (hba[ctlr]->sizes[i << gdev->minor_shift] != 0)
newhighest = i;
@@ -1789,7 +1972,8 @@
gdev->nr_real = h->highest_lun+1;
/* zero out the disk size info */
h->drv[logvol].nr_blks = 0;
- h->drv[logvol].blk_size = BLOCK_SIZE;
+ h->drv[logvol].cylinders = 0;
+ h->drv[logvol].blk_size = 0;
return(0);
}
@@ -1806,6 +1990,7 @@
cmdlist_t *c;
unsigned long flags;
ctlr_info_t *info_p = hba[ctlr];
+ DECLARE_COMPLETION(wait);
c = cmd_alloc(info_p, 0);
if(!c)
@@ -1835,6 +2020,7 @@
c->req.sg[0].addr = (__u32) pci_map_single(info_p->pci_dev,
buff, c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);
+ c->waiting = &wait;
/* Put the request on the tail of the request queue */
spin_lock_irqsave(&io_request_lock, flags);
addQ(&info_p->reqQ, c);
@@ -1843,8 +2029,7 @@
spin_unlock_irqrestore(&io_request_lock, flags);
/* Wait for completion */
- while(c->type != CMD_IOCTL_DONE)
- schedule();
+ wait_for_completion(&wait);
if (c->req.hdr.rcode & RCODE_FATAL) {
printk(KERN_WARNING "Fatal error on ida/c%dd%d\n",
@@ -1885,14 +2070,12 @@
return -EINVAL;
id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
- if(id_ldrive == NULL)
- {
+ if(id_ldrive == NULL) {
printk( KERN_ERR "cpqarray: out of memory.\n");
return -1;
}
id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
- if(id_lstatus_buf == NULL)
- {
+ if(id_lstatus_buf == NULL) {
kfree(id_ldrive);
printk( KERN_ERR "cpqarray: out of memory.\n");
return -1;
@@ -1905,8 +2088,7 @@
*/
ret_code = sendcmd_withirq(SENSE_LOG_DRV_STAT,
ctlr, id_lstatus_buf, size, 0, 0, logvol);
- if (ret_code == IO_ERROR)
- {
+ if (ret_code == IO_ERROR) {
/*
If can't get logical drive status, set
the logical drive map to 0, so the
@@ -1922,8 +2104,7 @@
/*
Make sure the logical drive is configured
*/
- if (id_lstatus_buf->status == LOG_NOT_CONF)
- {
+ if (id_lstatus_buf->status == LOG_NOT_CONF) {
printk(KERN_WARNING "cpqarray: c%dd%d array not configured\n",
ctlr, logvol);
kfree(id_lstatus_buf);
@@ -1937,8 +2118,7 @@
logical drive won't be set and
idastubopen will return error.
*/
- if (ret_code == IO_ERROR)
- {
+ if (ret_code == IO_ERROR) {
printk(KERN_WARNING "cpqarray: c%dd%d unable to ID logical volume\n",
ctlr,logvol);
kfree(id_lstatus_buf);
@@ -1963,8 +2143,7 @@
max_p = gdev->max_p;
start = logvol<< gdev->minor_shift;
- for(i=max_p-1; i>=0; i--)
- {
+ for(i=max_p-1; i>=0; i--) {
int minor = start+i;
invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
gdev->part[minor].start_sect = 0;
@@ -1972,6 +2151,7 @@
/* reset the blocksize so we can read the partition table */
blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+ hba[ctlr]->hardsizes[minor] = drv->blk_size;
}
++hba[ctlr]->log_drives;
gdev->nr_real = info_p->highest_lun + 1;
@@ -2075,8 +2255,7 @@
/* Command does not return anything, but idasend command needs a
buffer */
id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
- if(id_ctlr_buf==NULL)
- {
+ if(id_ctlr_buf==NULL) {
printk(KERN_WARNING "cpqarray: Out of memory. "
"Unable to start background processing.\n");
return;
@@ -2110,23 +2289,20 @@
info_p->log_drv_map = 0;
id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
- if(id_ldrive == NULL)
- {
+ if(id_ldrive == NULL) {
printk( KERN_ERR "cpqarray: out of memory.\n");
return;
}
id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
- if(id_ctlr_buf == NULL)
- {
+ if(id_ctlr_buf == NULL) {
kfree(id_ldrive);
printk( KERN_ERR "cpqarray: out of memory.\n");
return;
}
id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
- if(id_lstatus_buf == NULL)
- {
+ if(id_lstatus_buf == NULL) {
kfree(id_ctlr_buf);
kfree(id_ldrive);
printk( KERN_ERR "cpqarray: out of memory.\n");
@@ -2134,8 +2310,7 @@
}
sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
- if(sense_config_buf == NULL)
- {
+ if(sense_config_buf == NULL) {
kfree(id_lstatus_buf);
kfree(id_ctlr_buf);
kfree(id_ldrive);
@@ -2285,10 +2460,8 @@
pci_unregister_driver(&cpqarray_pci_driver);
/* double check that all controller entrys have been removed */
- for (i=0; i< MAX_CTLR; i++)
- {
- if (hba[i] != NULL)
- {
+ for (i=0; i< MAX_CTLR; i++) {
+ if (hba[i] != NULL) {
printk(KERN_WARNING "cpqarray: had to remove"
" controller %d\n", i);
cpqarray_remove_one_eisa(i);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)