Commit 13034f82 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] cpqarray: use PCI APIs

From: <mikem@beardog.cca.cpqcorp.net>

- Change to use pci APIs (change from 2.4.18 to 2.4.19)

  This also includes eisa detection fix during initialization which was
  missing from 2.4.19 but fixed in 2.4.25
parent 795c3847
...@@ -97,6 +97,34 @@ static struct board_type products[] = { ...@@ -97,6 +97,34 @@ static struct board_type products[] = {
{ 0x40580E11, "Smart Array 431", &smart4_access }, { 0x40580E11, "Smart Array 431", &smart4_access },
}; };
/* define the PCI info for the PCI cards this driver can control */
const struct pci_device_id cpqarray_pci_device_id[] =
{
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_COMPAQ_42XX,
0x0E11, 0x4058, 0, 0, 0}, /* SA431 */
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_COMPAQ_42XX,
0x0E11, 0x4051, 0, 0, 0}, /* SA4250ES */
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_COMPAQ_42XX,
0x0E11, 0x4050, 0, 0, 0}, /* SA4200 */
{ PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C1510,
0x0E11, 0x4048, 0, 0, 0}, /* LC2 */
{ PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C1510,
0x0E11, 0x4040, 0, 0, 0}, /* Integrated Array */
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,
0x0E11, 0x4034, 0, 0, 0}, /* SA 221 */
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,
0x0E11, 0x4033, 0, 0, 0}, /* SA 3100ES*/
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,
0x0E11, 0x4032, 0, 0, 0}, /* SA 3200*/
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,
0x0E11, 0x4031, 0, 0, 0}, /* SA 2SL*/
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,
0x0E11, 0x4030, 0, 0, 0}, /* SA 2P */
{ 0 }
};
MODULE_DEVICE_TABLE(pci, cpqarray_pci_device_id);
static struct gendisk *ida_gendisk[MAX_CTLR][NWD]; static struct gendisk *ida_gendisk[MAX_CTLR][NWD];
/* Debug... */ /* Debug... */
...@@ -108,7 +136,7 @@ static struct gendisk *ida_gendisk[MAX_CTLR][NWD]; ...@@ -108,7 +136,7 @@ static struct gendisk *ida_gendisk[MAX_CTLR][NWD];
/* Debug Extra Paranoid... */ /* Debug Extra Paranoid... */
#define DBGPX(s) do { } while(0) #define DBGPX(s) do { } while(0)
static int cpqarray_pci_detect(void); int cpqarray_init_step2(void);
static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev); static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev);
static void *remap_pci_mem(ulong base, ulong size); static void *remap_pci_mem(ulong base, ulong size);
static int cpqarray_eisa_detect(void); static int cpqarray_eisa_detect(void);
...@@ -119,6 +147,9 @@ static void start_fwbk(int ctlr); ...@@ -119,6 +147,9 @@ static void start_fwbk(int ctlr);
static cmdlist_t * cmd_alloc(ctlr_info_t *h, int get_from_pool); static cmdlist_t * cmd_alloc(ctlr_info_t *h, int get_from_pool);
static void cmd_free(ctlr_info_t *h, cmdlist_t *c, int got_from_pool); static void cmd_free(ctlr_info_t *h, cmdlist_t *c, int got_from_pool);
static void free_hba(int i);
static int alloc_cpqarray_hba(void);
static int sendcmd( static int sendcmd(
__u8 cmd, __u8 cmd,
int ctlr, int ctlr,
...@@ -145,6 +176,7 @@ static irqreturn_t do_ida_intr(int irq, void *dev_id, struct pt_regs * regs); ...@@ -145,6 +176,7 @@ static irqreturn_t do_ida_intr(int irq, void *dev_id, struct pt_regs * regs);
static void ida_timer(unsigned long tdata); static void ida_timer(unsigned long tdata);
static int ida_revalidate(struct gendisk *disk); static int ida_revalidate(struct gendisk *disk);
static int revalidate_allvol(ctlr_info_t *host); static int revalidate_allvol(ctlr_info_t *host);
static int cpqarray_register_ctlr(int ctlr, struct pci_dev *pdev);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static void ida_procinit(int i); static void ida_procinit(int i);
...@@ -281,20 +313,38 @@ static int ida_proc_get_info(char *buffer, char **start, off_t offset, int lengt ...@@ -281,20 +313,38 @@ static int ida_proc_get_info(char *buffer, char **start, off_t offset, int lengt
MODULE_PARM(eisa, "1-8i"); MODULE_PARM(eisa, "1-8i");
static void __exit cpqarray_exit(void) /* This is a bit of a hack,
* necessary to support both eisa and pci
*/
int __init cpqarray_init(void)
{ {
int i, j; if(cpqarray_init_step2() == 0) /* all the block dev num already used */
char buff[4]; return -ENODEV; /* or no controllers were found */
return 0;
}
static void release_io_mem(ctlr_info_t *c)
{
/* if IO mem was not protected do nothing */
if( c->io_mem_addr == 0)
return;
release_region(c->io_mem_addr, c->io_mem_length);
c->io_mem_addr = 0;
c->io_mem_length = 0;
}
for(i=0; i<nr_ctlr; i++) { static void __devexit cpqarray_remove_one(int i)
{
int j;
char buff[4];
/* sendcmd will turn off interrupt, and send the flush... /* sendcmd will turn off interrupt, and send the flush...
* To write all data in the battery backed cache to disks * To write all data in the battery backed cache to disks
* no data returned, but don't want to send NULL to sendcmd */ * 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 " printk(KERN_WARNING "Unable to flush cache on controller %d\n",
"controller %d\n", i); i);
} }
free_irq(hba[i]->intr, hba[i]); free_irq(hba[i]->intr, hba[i]);
iounmap(hba[i]->vaddr); iounmap(hba[i]->vaddr);
...@@ -305,73 +355,94 @@ static void __exit cpqarray_exit(void) ...@@ -305,73 +355,94 @@ static void __exit cpqarray_exit(void)
NR_CMDS * sizeof(cmdlist_t), (hba[i]->cmd_pool), NR_CMDS * sizeof(cmdlist_t), (hba[i]->cmd_pool),
hba[i]->cmd_pool_dhandle); hba[i]->cmd_pool_dhandle);
kfree(hba[i]->cmd_pool_bits); kfree(hba[i]->cmd_pool_bits);
for(j = 0; j < NWD; j++) {
for (j = 0; j < NWD; j++) {
if (ida_gendisk[i][j]->flags & GENHD_FL_UP) if (ida_gendisk[i][j]->flags & GENHD_FL_UP)
del_gendisk(ida_gendisk[i][j]); del_gendisk(ida_gendisk[i][j]);
devfs_remove("ida/c%dd%d",i,j); devfs_remove("ida/c%dd%d",i,j);
put_disk(ida_gendisk[i][j]); put_disk(ida_gendisk[i][j]);
} }
blk_cleanup_queue(hba[i]->queue); blk_cleanup_queue(hba[i]->queue);
release_io_mem(hba[i]);
free_hba(i);
}
static void __devexit cpqarray_remove_one_pci (struct pci_dev *pdev)
{
int i;
ctlr_info_t *tmp_ptr;
if (pci_get_drvdata(pdev) == NULL) {
printk( KERN_ERR "cpqarray: Unable to remove device \n");
return;
} }
devfs_remove("ida");
remove_proc_entry("cpqarray", proc_root_driver); tmp_ptr = pci_get_drvdata(pdev);
i = tmp_ptr->ctlr;
if (hba[i] == NULL) {
printk(KERN_ERR "cpqarray: controller %d appears to have"
"already been removed \n", i);
return;
}
pci_set_drvdata(pdev, NULL);
cpqarray_remove_one(i);
} }
/* /* removing an instance that was not removed automatically..
* This is it. Find all the controllers and register them. I really hate * must be an eisa card.
* stealing all these major device numbers.
* returns the number of block devices registered.
*/ */
static int __init cpqarray_init(void) static void __devexit cpqarray_remove_one_eisa (int i)
{ {
request_queue_t *q; if (hba[i] == NULL) {
int i,j; printk(KERN_ERR "cpqarray: controller %d appears to have"
int num_cntlrs_reg = 0; "already been removed \n", i);
/* detect controllers */ return;
cpqarray_pci_detect(); }
cpqarray_eisa_detect(); cpqarray_remove_one(i);
}
if (nr_ctlr == 0)
return -ENODEV;
printk(DRIVER_NAME "\n"); /* pdev is NULL for eisa */
printk("Found %d controller(s)\n", nr_ctlr); static int cpqarray_register_ctlr( int i, struct pci_dev *pdev)
{
request_queue_t *q;
int j;
/* allocate space for disk structs */
/* /*
* register block devices * register block devices
* Find disks and fill in structs * Find disks and fill in structs
* Get an interrupt, set the Q depth and get into /proc * Get an interrupt, set the Q depth and get into /proc
*/ */
for(i=0; i < nr_ctlr; i++) {
/* If this successful it should insure that we are the only */ /* If this successful it should insure that we are the only */
/* instance of the driver */ /* instance of the driver */
if (register_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname)) if (register_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname)) {
continue; goto Enomem4;
}
hba[i]->access.set_intr_mask(hba[i], 0); hba[i]->access.set_intr_mask(hba[i], 0);
if (request_irq(hba[i]->intr, do_ida_intr, if (request_irq(hba[i]->intr, do_ida_intr,
SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) { SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i]))
{
printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n",
hba[i]->intr, hba[i]->devname); hba[i]->intr, hba[i]->devname);
unregister_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname); goto Enomem3;
continue;
} }
num_cntlrs_reg++;
for (j=0; j<NWD; j++) { for (j=0; j<NWD; j++) {
ida_gendisk[i][j] = alloc_disk(1 << NWD_SHIFT); ida_gendisk[i][j] = alloc_disk(1 << NWD_SHIFT);
if (!ida_gendisk[i][j]) if (!ida_gendisk[i][j])
goto Enomem2; goto Enomem2;
} }
hba[i]->cmd_pool = (cmdlist_t *)pci_alloc_consistent( hba[i]->cmd_pool = (cmdlist_t *)pci_alloc_consistent(
hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t), hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t),
&(hba[i]->cmd_pool_dhandle)); &(hba[i]->cmd_pool_dhandle));
hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL); hba[i]->cmd_pool_bits = kmalloc(
((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long),
GFP_KERNEL);
if (!hba[i]->cmd_pool_bits || !hba[i]->cmd_pool) if (!hba[i]->cmd_pool_bits || !hba[i]->cmd_pool)
goto Enomem1; goto Enomem1;
memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t)); memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));
memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long)); memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));
printk(KERN_INFO "cpqarray: Finding drives on %s", printk(KERN_INFO "cpqarray: Finding drives on %s",
...@@ -390,6 +461,7 @@ static int __init cpqarray_init(void) ...@@ -390,6 +461,7 @@ static int __init cpqarray_init(void)
ida_procinit(i); ida_procinit(i);
if (pdev)
blk_queue_bounce_limit(q, hba[i]->pci_dev->dma_mask); blk_queue_bounce_limit(q, hba[i]->pci_dev->dma_mask);
/* This is a hardware imposed limit. */ /* This is a hardware imposed limit. */
...@@ -422,9 +494,9 @@ static int __init cpqarray_init(void) ...@@ -422,9 +494,9 @@ static int __init cpqarray_init(void)
disk->private_data = drv; disk->private_data = drv;
add_disk(disk); add_disk(disk);
} }
}
/* done ! */ /* done ! */
return num_cntlrs_reg ? 0 : -ENODEV; return(i);
Enomem1: Enomem1:
nr_ctlr = i; nr_ctlr = i;
...@@ -438,83 +510,102 @@ static int __init cpqarray_init(void) ...@@ -438,83 +510,102 @@ static int __init cpqarray_init(void)
ida_gendisk[i][j] = NULL; ida_gendisk[i][j] = NULL;
} }
free_irq(hba[i]->intr, hba[i]); free_irq(hba[i]->intr, hba[i]);
Enomem3:
unregister_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname); unregister_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname);
num_cntlrs_reg--; Enomem4:
if (pdev)
pci_set_drvdata(pdev, NULL);
release_io_mem(hba[i]);
free_hba(i);
printk( KERN_ERR "cpqarray: out of memory"); printk( KERN_ERR "cpqarray: out of memory");
if (!num_cntlrs_reg) { return -1;
remove_proc_entry("cpqarray", proc_root_driver); }
return -ENODEV;
static int __init cpqarray_init_one( struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int i;
printk(KERN_DEBUG "cpqarray: 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_cpqarray_hba();
if( i < 0 )
return (-1);
memset(hba[i], 0, sizeof(ctlr_info_t));
sprintf(hba[i]->devname, "ida%d", i);
hba[i]->ctlr = i;
/* Initialize the pdev driver private data */
pci_set_drvdata(pdev, hba[i]);
if (cpqarray_pci_init(hba[i], pdev) != 0) {
pci_set_drvdata(pdev, NULL);
release_io_mem(hba[i]);
free_hba(i);
return -1;
} }
return 0;
return (cpqarray_register_ctlr(i, pdev));
} }
static struct pci_driver cpqarray_pci_driver = {
name: "cpqarray",
probe: cpqarray_init_one,
remove: __devexit_p(cpqarray_remove_one_pci),
id_table: cpqarray_pci_device_id,
};
/* /*
* Find the controller and initialize it * This is it. Find all the controllers and register them. I really hate
* Cannot use the class code to search, because older array controllers use * stealing all these major device numbers.
* 0x018000 and new ones use 0x010400. So I might as well search for each * returns the number of block devices registered.
* each device IDs, being there are only going to be three of them.
*/ */
static int cpqarray_pci_detect(void) int __init cpqarray_init_step2(void)
{ {
struct pci_dev *pdev; int num_cntlrs_reg = 0;
int i;
#define IDA_BOARD_TYPES 3 /* detect controllers */
static int ida_vendor_id[IDA_BOARD_TYPES] = { PCI_VENDOR_ID_DEC, printk(DRIVER_NAME "\n");
PCI_VENDOR_ID_NCR, PCI_VENDOR_ID_COMPAQ }; pci_register_driver(&cpqarray_pci_driver);
static int ida_device_id[IDA_BOARD_TYPES] = { PCI_DEVICE_ID_COMPAQ_42XX, PCI_DEVICE_ID_NCR_53C1510, PCI_DEVICE_ID_COMPAQ_SMART2P }; cpqarray_eisa_detect();
int brdtype;
/* search for all PCI board types that could be for this driver */ for (i=0; i < MAX_CTLR; i++) {
for(brdtype=0; brdtype<IDA_BOARD_TYPES; brdtype++) if (hba[i] != NULL)
{ num_cntlrs_reg++;
pdev = pci_find_device(ida_vendor_id[brdtype],
ida_device_id[brdtype], NULL);
while (pdev) {
printk(KERN_DEBUG "cpqarray: Device 0x%x has"
" been found at bus %d dev %d func %d\n",
ida_vendor_id[brdtype],
pdev->bus->number, PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn));
if (nr_ctlr == 8) {
printk(KERN_WARNING "cpqarray: This driver"
" supports a maximum of 8 controllers.\n");
break;
} }
/* if it is a PCI_DEVICE_ID_NCR_53C1510, make sure it's the Compaq version of the chip */ return(num_cntlrs_reg);
}
if (ida_device_id[brdtype] == PCI_DEVICE_ID_NCR_53C1510) { /* Function to find the first free pointer into our hba[] array */
unsigned short subvendor=pdev->subsystem_vendor; /* Returns -1 if no free entries are left. */
if(subvendor != PCI_VENDOR_ID_COMPAQ) static int alloc_cpqarray_hba(void)
{ {
printk(KERN_DEBUG int i;
"cpqarray: not a Compaq integrated array controller\n");
continue;
}
}
hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); if(hba[nr_ctlr]==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) {
printk(KERN_ERR "cpqarray: out of memory.\n"); printk(KERN_ERR "cpqarray: out of memory.\n");
continue; return (-1);
}
memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
if (cpqarray_pci_init(hba[nr_ctlr], pdev) != 0)
{
kfree(hba[nr_ctlr]);
continue;
} }
sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); return (i);
hba[nr_ctlr]->ctlr = nr_ctlr;
nr_ctlr++;
pdev = pci_find_device(ida_vendor_id[brdtype],
ida_device_id[brdtype], pdev);
} }
} }
printk(KERN_WARNING "cpqarray: This driver supports a maximum"
" of 8 controllers.\n");
return(-1);
}
return nr_ctlr; static void free_hba(int i)
{
kfree(hba[i]);
hba[i]=NULL;
} }
/* /*
...@@ -556,6 +647,13 @@ static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev) ...@@ -556,6 +647,13 @@ static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
pci_read_config_dword(pdev, 0x2c, &board_id); pci_read_config_dword(pdev, 0x2c, &board_id);
/* check to see if controller has been disabled */
if(!(command & 0x02)) {
printk(KERN_WARNING
"cpqarray: controller appears to be disabled\n");
return(-1);
}
DBGINFO( DBGINFO(
printk("vendor_id = %x\n", vendor_id); printk("vendor_id = %x\n", vendor_id);
printk("device_id = %x\n", device_id); printk("device_id = %x\n", device_id);
...@@ -570,11 +668,28 @@ DBGINFO( ...@@ -570,11 +668,28 @@ DBGINFO(
); );
c->intr = irq; c->intr = irq;
c->io_mem_addr = addr[0];
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;
if(!request_region( c->io_mem_addr, c->io_mem_length,
"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;
}
break;
}
}
c->paddr = 0; c->paddr = 0;
for(i=0; i<6; i++) for(i=0; i<6; i++)
if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { if (!(pci_resource_flags(pdev, i) &
PCI_BASE_ADDRESS_SPACE_IO)) {
c->paddr = pci_resource_start (pdev, i); c->paddr = pci_resource_start (pdev, i);
break; break;
} }
...@@ -654,13 +769,13 @@ static int cpqarray_eisa_detect(void) ...@@ -654,13 +769,13 @@ static int cpqarray_eisa_detect(void)
int i=0, j; int i=0, j;
__u32 board_id; __u32 board_id;
int intr; int intr;
int ctlr;
int num_ctlr = 0;
while(i<8 && eisa[i]) { while(i<8 && eisa[i]) {
if (nr_ctlr == 8) { ctlr = alloc_cpqarray_hba();
printk(KERN_WARNING "cpqarray: This driver supports" if(ctlr == -1)
" a maximum of 8 controllers.\n");
break; break;
}
board_id = inl(eisa[i]+0xC80); board_id = inl(eisa[i]+0xC80);
for(j=0; j < NR_PRODUCTS; j++) for(j=0; j < NR_PRODUCTS; j++)
if (board_id == products[j].board_id) if (board_id == products[j].board_id)
...@@ -671,14 +786,21 @@ static int cpqarray_eisa_detect(void) ...@@ -671,14 +786,21 @@ static int cpqarray_eisa_detect(void)
" to access the SMART Array controller %08lx\n", (unsigned long)board_id); " to access the SMART Array controller %08lx\n", (unsigned long)board_id);
continue; continue;
} }
hba[nr_ctlr] = (ctlr_info_t *) kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
if(hba[nr_ctlr]==NULL) memset(hba[ctlr], 0, sizeof(ctlr_info_t));
hba[ctlr]->io_mem_addr = eisa[i];
hba[ctlr]->io_mem_length = 0x7FF;
if(!request_region(hba[ctlr]->io_mem_addr,
hba[ctlr]->io_mem_length,
"cpqarray"))
{ {
printk(KERN_ERR "cpqarray: out of memory.\n"); printk(KERN_WARNING "cpqarray: I/O range already in "
"use addr = %lx length = %ld\n",
hba[ctlr]->io_mem_addr,
hba[ctlr]->io_mem_length);
free_hba(ctlr);
continue; continue;
} }
memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
hba[nr_ctlr]->io_mem_addr = eisa[i];
/* /*
* Read the config register to find our interrupt * Read the config register to find our interrupt
...@@ -689,13 +811,13 @@ static int cpqarray_eisa_detect(void) ...@@ -689,13 +811,13 @@ static int cpqarray_eisa_detect(void)
else if (intr & 4) intr = 14; else if (intr & 4) intr = 14;
else if (intr & 8) intr = 15; else if (intr & 8) intr = 15;
hba[nr_ctlr]->intr = intr; hba[ctlr]->intr = intr;
sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); sprintf(hba[ctlr]->devname, "ida%d", nr_ctlr);
hba[nr_ctlr]->product_name = products[j].product_name; hba[ctlr]->product_name = products[j].product_name;
hba[nr_ctlr]->access = *(products[j].access); hba[ctlr]->access = *(products[j].access);
hba[nr_ctlr]->ctlr = nr_ctlr; hba[ctlr]->ctlr = ctlr;
hba[nr_ctlr]->board_id = board_id; hba[ctlr]->board_id = board_id;
hba[nr_ctlr]->pci_dev = NULL; /* not PCI */ hba[ctlr]->pci_dev = NULL; /* not PCI */
DBGINFO( DBGINFO(
printk("i = %d, j = %d\n", i, j); printk("i = %d, j = %d\n", i, j);
...@@ -704,14 +826,19 @@ DBGINFO( ...@@ -704,14 +826,19 @@ DBGINFO(
printk("board_id = %x\n", board_id); printk("board_id = %x\n", board_id);
); );
nr_ctlr++; num_ctlr++;
i++; i++;
if (cpqarray_register_ctlr(ctlr, NULL) == -1)
printk(KERN_WARNING
"cpqarray: Can't register EISA controller %d\n",
ctlr);
} }
return nr_ctlr; return num_ctlr;
} }
/* /*
* Open. Make sure the device is really there. * Open. Make sure the device is really there.
*/ */
...@@ -1721,5 +1848,24 @@ static void getgeometry(int ctlr) ...@@ -1721,5 +1848,24 @@ static void getgeometry(int ctlr)
} }
static void __exit cpqarray_exit(void)
{
int i;
pci_unregister_driver(&cpqarray_pci_driver);
/* Double check that all controller entries have been removed */
for(i=0; i<MAX_CTLR; i++) {
if (hba[i] != NULL) {
printk(KERN_WARNING "cpqarray: Removing EISA "
"controller %d\n", i);
cpqarray_remove_one_eisa(i);
}
}
devfs_remove("ida");
remove_proc_entry("cpqarray", proc_root_driver);
}
module_init(cpqarray_init) module_init(cpqarray_init)
module_exit(cpqarray_exit) module_exit(cpqarray_exit)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment