patch-2.4.5 linux/drivers/block/cciss.c
Next file: linux/drivers/block/cciss.h
Previous file: linux/drivers/block/blkpg.c
Back to the patch index
Back to the overall index
- Lines: 927
- Date:
Tue May 22 10:23:16 2001
- Orig file:
v2.4.4/linux/drivers/block/cciss.c
- Orig date:
Fri Apr 13 20:26:07 2001
diff -u --recursive --new-file v2.4.4/linux/drivers/block/cciss.c linux/drivers/block/cciss.c
@@ -44,8 +44,8 @@
#include <linux/genhd.h>
#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq CISS Driver (v 2.4.2)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,2)
+#define DRIVER_NAME "Compaq CISS Driver (v 2.4.5)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,5)
/* Embedded module documentation macros - see modules.h */
MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation");
@@ -55,6 +55,17 @@
#include "cciss.h"
#include <linux/cciss_ioctl.h>
+/* define the PCI info for the cards we can control */
+const struct pci_device_id cciss_pci_device_id[] = {
+ { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS,
+ 0x0E11, 0x4070, 0, 0, 0},
+ { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
+ 0x0E11, 0x4080, 0, 0, 0},
+ { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
+ 0x0E11, 0x4082, 0, 0, 0},
+};
+MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
+
#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type))
/* board_id = Subsystem Device ID & Vendor ID
@@ -73,7 +84,9 @@
#define READ_AHEAD 128
#define NR_CMDS 128 /* #commands that can be outstanding */
#define MAX_CTLR 8
-static int nr_ctlr;
+
+#define CCISS_DMA_MASK 0xFFFFFFFF /* 32 bit DMA */
+
static ctlr_info_t *hba[MAX_CTLR];
static struct proc_dir_entry *proc_cciss;
@@ -125,10 +138,10 @@
ctlr = h->ctlr;
size = sprintf(buffer, "%s: Compaq %s Controller\n"
- " Board ID: %08lx\n"
+ " Board ID: 0x%08lx\n"
" Firmware Version: %c%c%c%c\n"
- " Memory Address: %08lx\n"
- " IRQ: 0x%x\n"
+ " Memory Address: 0x%08lx\n"
+ " IRQ: %d\n"
" Logical drives: %d\n"
" Current Q depth: %d\n"
" Current # commands on controller %d\n"
@@ -172,7 +185,7 @@
static void __init cciss_procinit(int i)
{
if (proc_cciss == NULL) {
- proc_cciss = proc_mkdir("driver/cciss", NULL);
+ proc_cciss = proc_mkdir("cciss", proc_root_driver);
if (!proc_cciss)
return;
}
@@ -186,29 +199,32 @@
* For operations that cannot sleep, a command block is allocated at init,
* and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
* which ones are free or in use. For operations that can wait for kmalloc
- * to possible sleep, this routine can be called with a NULL pointer.
- * cmd_free() MUST be called with a NULL pointer if cmd_alloc was.
+ * to possible sleep, this routine can be called with get_from_pool set to 0.
+ * cmd_free() MUST be called with a got_from_pool set to 0 if cmd_alloc was.
*/
-static CommandList_struct * cmd_alloc(ctlr_info_t *h)
+static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
{
CommandList_struct *c;
int i;
u64bit temp64;
+ dma_addr_t cmd_dma_handle, err_dma_handle;
- if (h == NULL)
+ if (!get_from_pool)
{
- c = (CommandList_struct *)kmalloc(sizeof(CommandList_struct),
- GFP_KERNEL);
+ c = (CommandList_struct *) pci_alloc_consistent(
+ h->pdev, sizeof(CommandList_struct), &cmd_dma_handle);
if(c==NULL)
return NULL;
memset(c, 0, sizeof(CommandList_struct));
- c->err_info = (ErrorInfo_struct *)kmalloc(
- sizeof(ErrorInfo_struct), GFP_KERNEL);
+ c->err_info = (ErrorInfo_struct *)pci_alloc_consistent(
+ h->pdev, sizeof(ErrorInfo_struct),
+ &err_dma_handle);
if (c->err_info == NULL)
{
- kfree(c);
+ pci_free_consistent(h->pdev,
+ sizeof(CommandList_struct), c, cmd_dma_handle);
return NULL;
}
memset(c->err_info, 0, sizeof(ErrorInfo_struct));
@@ -223,18 +239,23 @@
printk(KERN_DEBUG "cciss: using command buffer %d\n", i);
#endif
c = h->cmd_pool + i;
- memset(c, 0, sizeof(CommandList_struct));
+ memset(c, 0, sizeof(CommandList_struct));
+ cmd_dma_handle = h->cmd_pool_dhandle
+ + i*sizeof(CommandList_struct);
c->err_info = h->errinfo_pool + i;
memset(c->err_info, 0, sizeof(ErrorInfo_struct));
+ err_dma_handle = h->errinfo_pool_dhandle
+ + i*sizeof(ErrorInfo_struct);
h->nr_allocs++;
}
-
- temp64.val = (__u64) virt_to_bus(c->err_info);
+ c->busaddr = (__u32) cmd_dma_handle;
+ temp64.val = (__u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower;
c->ErrDesc.Addr.upper = temp64.val32.upper;
c->ErrDesc.Len = sizeof(ErrorInfo_struct);
- c->busaddr = virt_to_bus(c);
+
+ c->ctlr = h->ctlr;
return c;
@@ -243,14 +264,19 @@
/*
* Frees a command block that was previously allocated with cmd_alloc().
*/
-static void cmd_free(ctlr_info_t *h, CommandList_struct *c)
+static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool)
{
int i;
+ u64bit temp64;
- if( h == NULL)
+ if( !got_from_pool)
{
- kfree(c->err_info);
- kfree(c);
+ temp64.val32.lower = c->ErrDesc.Addr.lower;
+ temp64.val32.upper = c->ErrDesc.Addr.upper;
+ pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct),
+ c->err_info, (dma_addr_t) temp64.val);
+ pci_free_consistent(h->pdev, sizeof(CommandList_struct),
+ c, (dma_addr_t) c->busaddr);
} else
{
i = c - h->cmd_pool;
@@ -390,8 +416,8 @@
cciss_pci_info_struct pciinfo;
if (!arg) return -EINVAL;
- pciinfo.bus = hba[ctlr]->pci_bus;
- pciinfo.dev_fn = hba[ctlr]->pci_dev_fn;
+ pciinfo.bus = hba[ctlr]->pdev->bus->number;
+ pciinfo.dev_fn = hba[ctlr]->pdev->devfn;
pciinfo.board_id = hba[ctlr]->board_id;
if (copy_to_user((void *) arg, &pciinfo, sizeof( cciss_pci_info_struct )))
return -EFAULT;
@@ -583,13 +609,10 @@
if (iocommand.Request.Type.Direction == XFER_WRITE)
{
/* Copy the data into the buffer we created */
- if (copy_from_user(buff, iocommand.buf,
- iocommand.buf_size)) {
- kfree(buff);
+ if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
return -EFAULT;
- }
}
- if ((c = cmd_alloc(NULL)) == NULL)
+ if ((c = cmd_alloc(h , 0)) == NULL)
{
kfree(buff);
return -ENOMEM;
@@ -615,8 +638,10 @@
// Fill in the scatter gather information
if (iocommand.buf_size > 0 )
- {
- temp64.val = (__u64) virt_to_bus(buff);
+ {
+ temp64.val = pci_map_single( h->pdev, buff,
+ iocommand.buf_size,
+ PCI_DMA_BIDIRECTIONAL);
c->SG[0].Addr.lower = temp64.val32.lower;
c->SG[0].Addr.upper = temp64.val32.upper;
c->SG[0].Len = iocommand.buf_size;
@@ -633,12 +658,18 @@
while(c->cmd_type != CMD_IOCTL_DONE)
schedule_timeout(1);
+ /* unlock the buffers from DMA */
+ temp64.val32.lower = c->SG[0].Addr.lower;
+ temp64.val32.upper = c->SG[0].Addr.upper;
+ pci_unmap_single( h->pdev, (dma_addr_t) temp64.val,
+ iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
+
/* Copy the error information out */
iocommand.error_info = *(c->err_info);
if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) )
{
- cmd_free(NULL, c);
kfree(buff);
+ cmd_free(h, c, 0);
return( -EFAULT);
}
@@ -647,13 +678,12 @@
/* Copy the data out of the buffer we created */
if (copy_to_user(iocommand.buf, buff, iocommand.buf_size))
{
- cmd_free(NULL, c);
- kfree(buff);
- return -EFAULT;
+ kfree(buff);
+ cmd_free(h, c, 0);
}
}
- cmd_free(NULL, c);
kfree(buff);
+ cmd_free(h, c, 0);
return(0);
}
@@ -691,13 +721,9 @@
max_p = gdev->max_p;
start = target << gdev->minor_shift;
- for(i=max_p; i>=0; i--) {
+ for(i=max_p-1; i>=0; i--) {
int minor = start+i;
- kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor);
- struct super_block *sb = get_super(devi);
- sync_dev(devi);
- if (sb) invalidate_inodes(sb);
- invalidate_buffers(devi);
+ invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
gdev->part[minor].start_sect = 0;
gdev->part[minor].nr_sects = 0;
@@ -820,9 +846,9 @@
int i;
unsigned long complete;
ctlr_info_t *info_p= hba[ctlr];
- u64bit temp64;
+ u64bit buff_dma_handle;
- c = cmd_alloc(info_p);
+ c = cmd_alloc(info_p, 1);
if (c == NULL)
{
printk(KERN_WARNING "cciss: unable to get memory");
@@ -903,15 +929,16 @@
printk(KERN_WARNING
"cciss: Unknown Command 0x%c sent attempted\n",
cmd);
- cmd_free(info_p, c);
+ cmd_free(info_p, c, 1);
return(IO_ERROR);
};
// Fill in the scatter gather information
if (size > 0 )
{
- temp64.val = (__u64) virt_to_bus(buff);
- c->SG[0].Addr.lower = temp64.val32.lower;
- c->SG[0].Addr.upper = temp64.val32.upper;
+ 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
}
@@ -947,6 +974,9 @@
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)
@@ -974,7 +1004,7 @@
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);
+ cmd_free(info_p,c, 1);
return(IO_ERROR);
}
}
@@ -982,7 +1012,7 @@
printk( KERN_WARNING "cciss cciss%d: SendCmd "
"Invalid command list address returned! (%lx)\n",
ctlr, complete);
- cmd_free(info_p, c);
+ cmd_free(info_p, c, 1);
return (IO_ERROR);
}
} else {
@@ -990,10 +1020,10 @@
"cciss cciss%d: SendCmd Timeout out, "
"No command list address returned!\n",
ctlr);
- cmd_free(info_p, c);
+ cmd_free(info_p, c, 1);
return (IO_ERROR);
}
- cmd_free(info_p, c);
+ cmd_free(info_p, c, 1);
return (IO_OK);
}
/*
@@ -1084,9 +1114,22 @@
static inline void complete_command( CommandList_struct *cmd, int timeout)
{
int status = 1;
-
+ int i;
+ 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_single(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 */
switch(cmd->err_info->CommandStatus)
@@ -1221,7 +1264,12 @@
struct list_head *queue_head = &q->queue_head;
struct request *creq;
u64bit temp64;
+ struct my_sg tmp_sg[MAXSGENTRIES];
+ int i;
+ // Loop till the queue is empty if or it is plugged
+ while (1)
+ {
if (q->plugged || list_empty(queue_head)) {
start_io(h);
return;
@@ -1231,7 +1279,7 @@
if (creq->nr_segments > MAXSGENTRIES)
BUG();
- if ((h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR) || (h->ctlr > nr_ctlr))
+ 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);
@@ -1241,7 +1289,7 @@
return;
}
- if (( c = cmd_alloc(h)) == NULL)
+ if (( c = cmd_alloc(h, 1)) == NULL)
{
start_io(h);
return;
@@ -1277,22 +1325,32 @@
sect += bh->b_size/512;
if (bh->b_data == lastdataend)
{ // tack it on to the last segment
- c->SG[seg-1].Len +=bh->b_size;
+ tmp_sg[seg-1].len +=bh->b_size;
lastdataend += bh->b_size;
} else
{
if (seg == MAXSGENTRIES)
BUG();
- c->SG[seg].Len = bh->b_size;
- temp64.val = (__u64) virt_to_bus(bh->b_data);
- c->SG[seg].Addr.lower = temp64.val32.lower;
- c->SG[seg].Addr.upper = temp64.val32.upper;
- c->SG[0].Ext = 0; // we are not chaining
+ tmp_sg[seg].len = bh->b_size;
+ tmp_sg[seg].start_addr = bh->b_data;
lastdataend = bh->b_data + bh->b_size;
seg++;
}
bh = bh->b_reqnext;
}
+ /* get the DMA records for the setup */
+ for (i=0; i<seg; i++)
+ {
+ c->SG[i].Len = tmp_sg[i].len;
+ temp64.val = (__u64) pci_map_single( h->pdev,
+ tmp_sg[i].start_addr,
+ tmp_sg[i].len,
+ (c->Request.Type.Direction == XFER_READ) ?
+ PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+ c->SG[i].Addr.lower = temp64.val32.lower;
+ c->SG[i].Addr.upper = temp64.val32.upper;
+ c->SG[i].Ext = 0; // we are not chaining
+ }
/* track how many SG entries we are using */
if( seg > h->maxSG)
h->maxSG = seg;
@@ -1329,7 +1387,7 @@
h->Qdepth++;
if(h->Qdepth > h->maxQsinceinit)
h->maxQsinceinit = h->Qdepth;
- start_io(h);
+ } // while loop
}
static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
@@ -1373,7 +1431,7 @@
removeQ(&h->cmpQ, c);
if (c->cmd_type == CMD_RWREQ) {
complete_command(c, 0);
- cmd_free(h, c);
+ cmd_free(h, c, 1);
} else if (c->cmd_type == CMD_IOCTL_PEND) {
c->cmd_type = CMD_IOCTL_DONE;
}
@@ -1427,20 +1485,18 @@
}
#endif /* CCISS_DEBUG */
-static int cciss_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn)
+static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
{
ushort vendor_id, device_id, command;
unchar cache_line_size, latency_timer;
unchar irq, revision;
uint addr[6];
__u32 board_id;
- struct pci_dev *pdev;
int cfg_offset;
int cfg_base_addr;
int cfg_base_addr_index;
int i;
- pdev = pci_find_slot(bus, device_fn);
vendor_id = pdev->vendor;
device_id = pdev->device;
irq = pdev->irq;
@@ -1449,7 +1505,15 @@
addr[i] = pdev->resource[i].start;
if (pci_enable_device(pdev))
+ {
+ printk(KERN_ERR "cciss: Unable to Enable PCI device\n");
return( -1);
+ }
+ if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0)
+ {
+ printk(KERN_ERR "cciss: Unable to set DMA mask\n");
+ return(-1);
+ }
(void) pci_read_config_word(pdev, PCI_COMMAND,&command);
(void) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
@@ -1566,59 +1630,6 @@
return 0;
}
-/*
- * Scans PCI space for any controllers that this driver can control.
- */
-static int cciss_pci_detect(void)
-{
-
- int index;
- unchar bus=0, dev_fn=0;
-
- #define CCISS_BOARD_TYPES 2
- static int cciss_device_id[CCISS_BOARD_TYPES] = {
- PCI_DEVICE_ID_COMPAQ_CISS, PCI_DEVICE_ID_COMPAQ_CISSB};
- int brdtype;
-
- /* search for all PCI board types that could be for this driver */
- for(brdtype=0; brdtype<CCISS_BOARD_TYPES; brdtype++)
- {
- for(index=0; ; index++) {
- if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ,
- cciss_device_id[brdtype],
- index, &bus, &dev_fn))
- break;
- printk(KERN_DEBUG "cciss: Device %x has been found at %x %x\n",
- cciss_device_id[brdtype], bus, dev_fn);
- if (index == 1000000) break;
- if (nr_ctlr == 8) {
- printk(KERN_WARNING "cciss: This driver"
- " supports a maximum of 8 controllers.\n");
- break;
- }
- hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
- if(hba[nr_ctlr]==NULL)
- {
- printk(KERN_ERR "cciss: out of memory.\n");
- continue;
- }
- memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
- if (cciss_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
- {
- kfree(hba[nr_ctlr]);
- continue;
- }
- sprintf(hba[nr_ctlr]->devname, "cciss%d", nr_ctlr);
- hba[nr_ctlr]->ctlr = nr_ctlr;
- hba[nr_ctlr]->pci_bus = bus;
- hba[nr_ctlr]->pci_dev_fn = dev_fn;
- nr_ctlr++;
-
- }
- }
- return nr_ctlr;
-
-}
/*
* Gets information about the local volumes attached to the controller.
@@ -1797,166 +1808,265 @@
kfree(size_buff);
}
+/* Function to find the first free pointer into our hba[] array */
+/* Returns -1 if no free entries are left. */
+static int alloc_cciss_hba(void)
+{
+ int i;
+ for(i=0; i< MAX_CTLR; i++)
+ {
+ if (hba[i] == NULL)
+ {
+ hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+ if(hba[i]==NULL)
+ {
+ printk(KERN_ERR "cciss: out of memory.\n");
+ return (-1);
+ }
+ return (i);
+ }
+ }
+ printk(KERN_WARNING "cciss: This driver supports a maximum"
+ " of 8 controllers.\n");
+ return(-1);
+}
+
+static void free_hba(int i)
+{
+ kfree(hba[i]);
+ hba[i]=NULL;
+}
+
/*
* This is it. Find all the controllers and register them. I really hate
* stealing all these major device numbers.
* returns the number of block devices registered.
*/
-int __init cciss_init(void)
+static int __init cciss_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- int num_cntlrs_reg = 0;
- int i,j;
request_queue_t *q;
+ int i;
+ int j;
- /* detect controllers */
- cciss_pci_detect();
-
- if (nr_ctlr == 0)
- return(num_cntlrs_reg);
-
- printk(KERN_INFO DRIVER_NAME "\n");
- printk(KERN_INFO "Found %d controller(s)\n", nr_ctlr);
- for(i=0;i<nr_ctlr;i++)
+ printk(KERN_DEBUG "cciss: Device 0x%x has been found at"
+ " bus %d dev %d func %d\n",
+ pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
+ i = alloc_cciss_hba();
+ if( i < 0 )
+ return (-1);
+ memset(hba[i], 0, sizeof(ctlr_info_t));
+ if (cciss_pci_init(hba[i], pdev) != 0)
+ {
+ free_hba(i);
+ return (-1);
+ }
+ sprintf(hba[i]->devname, "cciss%d", i);
+ hba[i]->ctlr = i;
+ hba[i]->pdev = pdev;
+
+ if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops))
{
- if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops))
- {
- printk(KERN_ERR "cciss: Unable to get major number "
- "%d for %s\n", MAJOR_NR+i, hba[i]->devname);
- continue;
- }
- /* make sure the board interrupts are off */
- hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
- if( request_irq(hba[i]->intr, do_cciss_intr, SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i]))
- {
- printk(KERN_ERR "ciss: Unable to get irq %d for %s\n",
- hba[i]->intr, hba[i]->devname);
- unregister_blkdev( MAJOR_NR+i, hba[i]->devname);
- continue;
- }
- num_cntlrs_reg++;
- hba[i]->cmd_pool_bits = (__u32*)kmalloc(
- ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
- hba[i]->cmd_pool = (CommandList_struct *)kmalloc(
- NR_CMDS * sizeof(CommandList_struct),
- GFP_KERNEL);
- hba[i]->errinfo_pool = (ErrorInfo_struct *)kmalloc(
- NR_CMDS * sizeof( ErrorInfo_struct),
- GFP_KERNEL);
- if((hba[i]->cmd_pool_bits == NULL)
- || (hba[i]->cmd_pool == NULL)
- || (hba[i]->errinfo_pool == NULL))
- {
- nr_ctlr = i;
- kfree(hba[i]->cmd_pool_bits);
- kfree(hba[i]->cmd_pool);
- kfree(hba[i]->errinfo_pool);
- free_irq(hba[i]->intr, hba[i]);
- unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
- num_cntlrs_reg--;
- printk( KERN_ERR "cciss: out of memory");
- return(num_cntlrs_reg);
- }
-
- /* command and error info recs zeroed out before
+ printk(KERN_ERR "cciss: Unable to get major number "
+ "%d for %s\n", MAJOR_NR+i, hba[i]->devname);
+ free_hba(i);
+ return(-1);
+ }
+ /* make sure the board interrupts are off */
+ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
+ if( request_irq(hba[i]->intr, do_cciss_intr,
+ SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i]))
+ {
+ printk(KERN_ERR "ciss: Unable to get irq %d for %s\n",
+ hba[i]->intr, hba[i]->devname);
+ unregister_blkdev( MAJOR_NR+i, hba[i]->devname);
+ free_hba(i);
+ return(-1);
+ }
+ hba[i]->cmd_pool_bits = (__u32*)kmalloc(
+ ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
+ hba[i]->cmd_pool = (CommandList_struct *)pci_alloc_consistent(
+ hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
+ &(hba[i]->cmd_pool_dhandle));
+ hba[i]->errinfo_pool = (ErrorInfo_struct *)pci_alloc_consistent(
+ hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
+ &(hba[i]->errinfo_pool_dhandle));
+ if((hba[i]->cmd_pool_bits == NULL)
+ || (hba[i]->cmd_pool == NULL)
+ || (hba[i]->errinfo_pool == NULL))
+ {
+ if(hba[i]->cmd_pool_bits)
+ kfree(hba[i]->cmd_pool_bits);
+ if(hba[i]->cmd_pool)
+ pci_free_consistent(hba[i]->pdev,
+ NR_CMDS * sizeof(CommandList_struct),
+ hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
+ if(hba[i]->errinfo_pool)
+ pci_free_consistent(hba[i]->pdev,
+ NR_CMDS * sizeof( ErrorInfo_struct),
+ hba[i]->errinfo_pool,
+ hba[i]->errinfo_pool_dhandle);
+ free_irq(hba[i]->intr, hba[i]);
+ unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+ free_hba(i);
+ printk( KERN_ERR "cciss: out of memory");
+ return(-1);
+ }
+
+ /* Initialize the pdev driver private data.
+ have it point to hba[i]. */
+ pdev->driver_data = hba[i];
+ /* command and error info recs zeroed out before
they are used */
- memset(hba[i]->cmd_pool_bits, 0,
- ((NR_CMDS+31)/32)*sizeof(__u32));
+ memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32));
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i);
+ printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i);
#endif /* CCISS_DEBUG */
- cciss_getgeometry(i);
+ cciss_getgeometry(i);
- /* Turn the interrupts on so we can service requests */
- hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON);
+ /* Turn the interrupts on so we can service requests */
+ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON);
- cciss_procinit(i);
+ cciss_procinit(i);
- q = BLK_DEFAULT_QUEUE(MAJOR_NR + i);
- q->queuedata = hba[i];
- blk_init_queue(q, do_cciss_request);
- blk_queue_headactive(q, 0);
-
- /* fill in the other Kernel structs */
- blksize_size[MAJOR_NR+i] = hba[i]->blocksizes;
- hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes;
- read_ahead[MAJOR_NR+i] = READ_AHEAD;
-
- /* Set the pointers to queue functions */
- q->back_merge_fn = cpq_back_merge_fn;
- q->front_merge_fn = cpq_front_merge_fn;
- q->merge_requests_fn = cpq_merge_requests_fn;
-
-
- /* Fill in the gendisk data */
- hba[i]->gendisk.major = MAJOR_NR + i;
- hba[i]->gendisk.major_name = "cciss";
- hba[i]->gendisk.minor_shift = NWD_SHIFT;
- hba[i]->gendisk.max_p = MAX_PART;
- hba[i]->gendisk.part = hba[i]->hd;
- hba[i]->gendisk.sizes = hba[i]->sizes;
- hba[i]->gendisk.nr_real = hba[i]->num_luns;
-
- /* Get on the disk list */
- hba[i]->gendisk.next = gendisk_head;
- gendisk_head = &(hba[i]->gendisk);
-
- cciss_geninit(i);
- for(j=0; j<NWD; j++)
- register_disk(&(hba[i]->gendisk),
- MKDEV(MAJOR_NR+i, j <<4),
- MAX_PART, &cciss_fops,
- hba[i]->drv[j].nr_blocks);
- }
- return(nr_ctlr);
-}
+ q = BLK_DEFAULT_QUEUE(MAJOR_NR + i);
+ q->queuedata = hba[i];
+ blk_init_queue(q, do_cciss_request);
+ blk_queue_headactive(q, 0);
-EXPORT_NO_SYMBOLS;
+ /* fill in the other Kernel structs */
+ blksize_size[MAJOR_NR+i] = hba[i]->blocksizes;
+ hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes;
+ read_ahead[MAJOR_NR+i] = READ_AHEAD;
-/* This is a bit of a hack... */
-static int __init init_cciss_module(void)
-{
+ /* Set the pointers to queue functions */
+ q->back_merge_fn = cpq_back_merge_fn;
+ q->front_merge_fn = cpq_front_merge_fn;
+ q->merge_requests_fn = cpq_merge_requests_fn;
- if (cciss_init() == 0) /* all the block dev numbers already used */
- return -EIO; /* or no controllers were found */
- return 0;
+
+ /* Fill in the gendisk data */
+ hba[i]->gendisk.major = MAJOR_NR + i;
+ hba[i]->gendisk.major_name = "cciss";
+ hba[i]->gendisk.minor_shift = NWD_SHIFT;
+ hba[i]->gendisk.max_p = MAX_PART;
+ hba[i]->gendisk.part = hba[i]->hd;
+ hba[i]->gendisk.sizes = hba[i]->sizes;
+ hba[i]->gendisk.nr_real = hba[i]->num_luns;
+
+ /* Get on the disk list */
+ hba[i]->gendisk.next = gendisk_head;
+ gendisk_head = &(hba[i]->gendisk);
+
+ cciss_geninit(i);
+ for(j=0; j<NWD; j++)
+ register_disk(&(hba[i]->gendisk),
+ MKDEV(MAJOR_NR+i, j <<4),
+ MAX_PART, &cciss_fops,
+ hba[i]->drv[j].nr_blocks);
+
+ return(1);
}
-static void __exit cleanup_cciss_module(void)
+static void __devexit cciss_remove_one (struct pci_dev *pdev)
{
+ ctlr_info_t *tmp_ptr;
int i;
struct gendisk *g;
- for(i=0; i<nr_ctlr; i++)
+ if (pdev->driver_data == NULL)
+ {
+ printk( KERN_ERR "cciss: Unable to remove device \n");
+ return;
+ }
+ tmp_ptr = (ctlr_info_t *) pdev->driver_data;
+ i = tmp_ptr->ctlr;
+ if (hba[i] == NULL)
{
- /* Turn board interrupts off */
- hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
- free_irq(hba[i]->intr, hba[i]);
- iounmap((void*)hba[i]->vaddr);
- unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
- remove_proc_entry(hba[i]->devname, proc_cciss);
+ printk(KERN_ERR "cciss: device appears to "
+ "already be removed \n");
+ return;
+ }
+ /* Turn board interrupts off */
+ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
+ free_irq(hba[i]->intr, hba[i]);
+ pdev->driver_data = NULL;
+ iounmap((void*)hba[i]->vaddr);
+ unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+ remove_proc_entry(hba[i]->devname, proc_cciss);
+
- /* remove it from the disk list */
- if (gendisk_head == &(hba[i]->gendisk))
- {
- gendisk_head = hba[i]->gendisk.next;
- } else
+ /* remove it from the disk list */
+ if (gendisk_head == &(hba[i]->gendisk))
+ {
+ gendisk_head = hba[i]->gendisk.next;
+ } else
+ {
+ for(g=gendisk_head; g ; g=g->next)
{
- for(g=gendisk_head; g ; g=g->next)
+ if(g->next == &(hba[i]->gendisk))
{
- if(g->next == &(hba[i]->gendisk))
- {
- g->next = hba[i]->gendisk.next;
- }
+ g->next = hba[i]->gendisk.next;
}
}
- remove_proc_entry("driver/cciss", &proc_root);
- kfree(hba[i]->cmd_pool);
- kfree(hba[i]->errinfo_pool);
- kfree(hba[i]->cmd_pool_bits);
- kfree(hba[i]);
}
+ pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
+ hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
+ pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
+ hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
+ kfree(hba[i]->cmd_pool_bits);
+ free_hba(i);
+}
+
+static struct pci_driver cciss_pci_driver = {
+ name: "cciss",
+ probe: cciss_init_one,
+ remove: cciss_remove_one,
+ id_table: cciss_pci_device_id, /* id_table */
+};
+
+/*
+* This is it. Register the PCI driver information for the cards we control
+* the OS will call our registered routines when it finds one of our cards.
+*/
+int __init cciss_init(void)
+{
+
+ printk(KERN_INFO DRIVER_NAME "\n");
+ /* Register for out PCI devices */
+ if (pci_register_driver(&cciss_pci_driver) > 0 )
+ return 0;
+ else
+ return -ENODEV;
+
+ }
+
+EXPORT_NO_SYMBOLS;
+static int __init init_cciss_module(void)
+{
+
+ return ( cciss_init());
+}
+
+static void __exit cleanup_cciss_module(void)
+{
+ int i;
+
+ pci_unregister_driver(&cciss_pci_driver);
+ /* double check that all controller entrys have been removed */
+ for (i=0; i< MAX_CTLR; i++)
+ {
+ if (hba[i] != NULL)
+ {
+ printk(KERN_WARNING "cciss: had to remove"
+ " controller %d\n", i);
+ cciss_remove_one(hba[i]->pdev);
+ }
+ }
+ remove_proc_entry("cciss", proc_root_driver);
}
module_init(init_cciss_module);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)