--- linux-2.6.8.1-t047-cciss/drivers/block/cciss.c 2005-11-22 18:01:33.205086568 +0300 +++ rhel4u2/drivers/block/cciss.c 2005-10-19 11:47:13.000000000 +0400 @@ -1,6 +1,6 @@ /* * Disk Array driver for HP SA 5xxx and 6xxx Controllers - * Copyright 2000, 2002 Hewlett-Packard Development Company, L.P. + * Copyright 2000, 2005 Hewlett-Packard Development Company, L.P. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,14 +46,15 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "Compaq CISS Driver (v 2.6.2)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,2) +#define DRIVER_NAME "HP CISS Driver (v 2.6.8)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,8) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); -MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.2"); +MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.8"); +MODULE_VERSION("2.6.8"); MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" - " SA6i"); + " SA6i P600 P800 P400 E200 E200i"); MODULE_LICENSE("GPL"); #include "cciss_cmd.h" @@ -80,10 +81,24 @@ const struct pci_device_id cciss_pci_dev 0x0E11, 0x409D, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x4091, 0, 0, 0}, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, - 0x0E11, 0x409E, 0, 0, 0}, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA, + 0x103C, 0x3225, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, + 0x103C, 0x3223, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, + 0x103C, 0x3234, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, + 0x103C, 0x3235, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3211, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, + 0x103C, 0x3212, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, + 0x103C, 0x3213, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, + 0x103C, 0x3214, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, + 0x103C, 0x3215, 0, 0, 0}, {0,} }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); @@ -104,8 +119,15 @@ static struct board_type products[] = { { 0x409C0E11, "Smart Array 6400", &SA5_access}, { 0x409D0E11, "Smart Array 6400 EM", &SA5_access}, { 0x40910E11, "Smart Array 6i", &SA5_access}, - { 0x409E0E11, "Smart Array 6422", &SA5_access}, - { 0x3211103C, "Smart Array V100", &SA5_access}, + { 0x3225103C, "Smart Array P600", &SA5_access}, + { 0x3223103C, "Smart Array P800", &SA5_access}, + { 0x3234103C, "Smart Array P400", &SA5_access}, + { 0x3235103C, "Smart Array P400i", &SA5_access}, + { 0x3211103C, "Smart Array E200i", &SA5_access}, + { 0x3212103C, "Smart Array E200", &SA5_access}, + { 0x3213103C, "Smart Array E200i", &SA5_access}, + { 0x3214103C, "Smart Array E200i", &SA5_access}, + { 0x3215103C, "Smart Array E200i", &SA5_access}, }; /* How long to wait (in millesconds) for board to go into simple mode */ @@ -115,9 +137,13 @@ static struct board_type products[] = { /*define how many times we will try a command because of bus resets */ #define MAX_CMD_RETRIES 3 -#define READ_AHEAD 256 +#define READ_AHEAD 1024 #define NR_CMDS 384 /* #commands that can be outstanding */ -#define MAX_CTLR 8 +#define MAX_CTLR 32 + +/* Originally cciss driver only supports 8 major numbers */ +#define MAX_CTLR_ORIG 8 + #define CCISS_DMA_MASK 0xFFFFFFFF /* 32 bit DMA */ @@ -192,10 +218,10 @@ static inline CommandList_struct *remove /* * Report information about this controller. */ -#define ENG_GIG 1048576000 +#define ENG_GIG 1000000000 #define ENG_GIG_FACTOR (ENG_GIG/512) #define RAID_UNKNOWN 6 -static const char *raid_label[] = {"0","4","1(0+1)","5","5+1","ADG", +static const char *raid_label[] = {"0","4","1(1+0)","5","5+1","ADG", "UNKNOWN"}; static struct proc_dir_entry *proc_cciss; @@ -209,7 +235,7 @@ static int cciss_proc_get_info(char *buf ctlr_info_t *h = (ctlr_info_t*)data; drive_info_struct *drv; unsigned long flags; - unsigned int vol_sz, vol_sz_frac; + sector_t vol_sz, vol_sz_frac; ctlr = h->ctlr; @@ -246,32 +272,21 @@ static int cciss_proc_get_info(char *buf pos += size; len += size; cciss_proc_tape_report(ctlr, buffer, &pos, &len); for(i=0; i<=h->highest_lun; i++) { - sector_t tmp; drv = &h->drv[i]; if (drv->block_size == 0) continue; - vol_sz = drv->nr_blocks; - sector_div(vol_sz, ENG_GIG_FACTOR); - - /* - * Awkwardly do this: - * vol_sz_frac = - * (drv->nr_blocks%ENG_GIG_FACTOR)*100/ENG_GIG_FACTOR; - */ - tmp = drv->nr_blocks; - vol_sz_frac = sector_div(tmp, ENG_GIG_FACTOR); - - /* Now, vol_sz_frac = (drv->nr_blocks%ENG_GIG_FACTOR) */ + vol_sz = drv->nr_blocks; + vol_sz_frac = sector_div(vol_sz, ENG_GIG_FACTOR); vol_sz_frac *= 100; sector_div(vol_sz_frac, ENG_GIG_FACTOR); if (drv->raid_level > 5) drv->raid_level = RAID_UNKNOWN; size = sprintf(buffer+len, "cciss/c%dd%d:" - "\t%4d.%02dGB\tRAID %s\n", - ctlr, i, vol_sz,vol_sz_frac, + "\t%4u.%02uGB\tRAID %s\n", + ctlr, i, (int)vol_sz, (int)vol_sz_frac, raid_label[drv->raid_level]); pos += size; len += size; } @@ -449,13 +464,22 @@ static int cciss_open(struct inode *inod /* * Root is allowed to open raw volume zero even if it's not configured - * so array config can still work. I don't think I really like this, + * so array config can still work. Root is also allowed to open any + * volume that has a LUN ID, so it can issue IOCTL to reread the + * disk information. 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 (drv->nr_blocks == 0) { - if (iminor(inode) != 0) + if (iminor(inode) != 0) { /* not node 0? */ + /* if not node 0 make sure it is a partition = 0 */ + if (iminor(inode) & 0x0f) { return -ENXIO; + /* if it is, make sure we have a LUN ID */ + } else if (drv->LunID == 0) { + return -ENXIO; + } + } if (!capable(CAP_SYS_ADMIN)) return -EPERM; } @@ -578,7 +602,7 @@ int cciss_ioctl32_passthru(unsigned int err = sys_ioctl(fd, CCISS_PASSTHRU, (unsigned long) p); if (err) return err; - err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(&arg32->error_info)); + err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info)); if (err) return -EFAULT; return err; @@ -610,7 +634,7 @@ int cciss_ioctl32_big_passthru(unsigned err = sys_ioctl(fd, CCISS_BIG_PASSTHRU, (unsigned long) p); if (err) return err; - err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(&arg32->error_info)); + err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info)); if (err) return -EFAULT; return err; @@ -657,6 +681,7 @@ static int cciss_ioctl(struct inode *ino cciss_pci_info_struct pciinfo; if (!arg) return -EINVAL; + pciinfo.domain = pci_domain_nr(host->pdev->bus); pciinfo.bus = host->pdev->bus->number; pciinfo.dev_fn = host->pdev->devfn; pciinfo.board_id = host->board_id; @@ -810,7 +835,7 @@ static int cciss_ioctl(struct inode *ino luninfo.num_opens = drv->usage_count; luninfo.num_parts = 0; /* count partitions 1 to 15 with sizes > 0 */ - for(i=1; i part[i]) continue; if (disk->part[i]->nr_sects != 0) @@ -866,6 +891,8 @@ static int cciss_ioctl(struct inode *ino kfree(buff); return -EFAULT; } + } else { + memset(buff, 0, iocommand.buf_size); } if ((c = cmd_alloc(host , 0)) == NULL) { @@ -1012,6 +1039,8 @@ static int cciss_ioctl(struct inode *ino 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; @@ -1097,18 +1126,11 @@ cleanup1: return(status); } default: - return -EBADRQC; + return -ENOTTY; } } -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 @@ -1160,7 +1182,9 @@ static int revalidate_allvol(ctlr_info_t for (i = 0; i < NWD; i++) { struct gendisk *disk = host->gendisk[i]; drive_info_struct *drv = &(host->drv[i]); - if (!drv->nr_blocks) + /* we must register the controller even if no disks exist */ + /* this is for the online array utilities */ + if (!drv->heads && i) continue; blk_queue_hardsect_size(host->queue, drv->block_size); set_capacity(disk, drv->nr_blocks); @@ -1477,21 +1501,22 @@ static void cciss_geometry_inquiry(int c drv->sectors = 32; // Sectors per track drv->cylinders = total_size / 255 / 32; } else { + unsigned int t; + drv->block_size = block_size; drv->nr_blocks = total_size; drv->heads = inq_buff->data_byte[6]; drv->sectors = inq_buff->data_byte[7]; drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8; drv->cylinders += inq_buff->data_byte[5]; + drv->raid_level = inq_buff->data_byte[8]; + t = drv->heads * drv->sectors; + if (t > 1) { + drv->cylinders = total_size/t; + } } } else { /* Get geometry failed */ - printk(KERN_WARNING "cciss: reading geometry failed, " - "continuing with default geometry\n"); - drv->block_size = block_size; - drv->nr_blocks = total_size; - drv->heads = 255; - drv->sectors = 32; // Sectors per track - drv->cylinders = total_size / 255 / 32; + printk(KERN_WARNING "cciss: reading geometry failed\n"); } printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n", drv->heads, drv->sectors, drv->cylinders); @@ -1509,8 +1534,8 @@ cciss_read_capacity(int ctlr, int logvol return_code = sendcmd(CCISS_READ_CAPACITY, ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD); if (return_code == IO_OK) { - *total_size = be32_to_cpu(*((__u32 *) &buf->total_size[0]))+1; - *block_size = be32_to_cpu(*((__u32 *) &buf->block_size[0])); + *total_size = be32_to_cpu(*((__be32 *) &buf->total_size[0]))+1; + *block_size = be32_to_cpu(*((__be32 *) &buf->block_size[0])); } else { /* read capacity command failed */ printk(KERN_WARNING "cciss: read capacity failed\n"); *total_size = 0; @@ -1520,6 +1545,7 @@ cciss_read_capacity(int ctlr, int logvol *total_size, *block_size); return; } + static int register_new_disk(ctlr_info_t *h) { struct gendisk *disk; @@ -1663,7 +1689,9 @@ static int register_new_disk(ctlr_info_t /* setup partitions per disk */ disk = h->gendisk[logvol]; set_capacity(disk, h->drv[logvol].nr_blocks); - add_disk(disk); + /* if it's the controller it's already added */ + if(logvol) + add_disk(disk); freeret: kfree(ld_buff); kfree(size_buff); @@ -1675,6 +1703,53 @@ free_err: logvol = -1; goto freeret; } + +static int cciss_revalidate(struct gendisk *disk) +{ + ctlr_info_t *h = get_host(disk); + drive_info_struct *drv = get_drv(disk); + int logvol; + int FOUND=0; + unsigned int block_size; + unsigned int total_size; + ReadCapdata_struct *size_buff = NULL; + InquiryData_struct *inq_buff = NULL; + + for(logvol=0; logvol < CISS_MAX_LUN; logvol++) + { + if(h->drv[logvol].LunID == drv->LunID) { + FOUND=1; + break; + } + } + + if (!FOUND) return 1; + + size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); + if (size_buff == NULL) + { + printk(KERN_WARNING "cciss: out of memory\n"); + return 1; + } + inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); + if (inq_buff == NULL) + { + printk(KERN_WARNING "cciss: out of memory\n"); + kfree(size_buff); + return 1; + } + + cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size, &block_size); + cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, inq_buff, drv); + + blk_queue_hardsect_size(h->queue, drv->block_size); + set_capacity(disk, drv->nr_blocks); + + kfree(size_buff); + kfree(inq_buff); + return 0; +} + /* * Wait polling for a command to complete. * The memory mapped FIFO is polled for the completion. @@ -1844,13 +1919,13 @@ cleanup1: /* * Map (physical) PCI mem into (virtual) kernel space */ -static ulong remap_pci_mem(ulong base, ulong size) +static void __iomem *remap_pci_mem(ulong base, ulong size) { ulong page_base = ((ulong) base) & PAGE_MASK; ulong page_offs = ((ulong) base) - page_base; - ulong page_remapped = (ulong) ioremap(page_base, page_offs+size); + void __iomem *page_remapped = ioremap(page_base, page_offs+size); - return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL); + return page_remapped ? (page_remapped + page_offs) : NULL; } /* @@ -2061,6 +2136,9 @@ static void do_cciss_request(request_que drive_info_struct *drv; int i, dir; + /* We call start_io here in case there is a command waiting on the + * queue that has not been sent. + */ if (blk_queue_plugged(q)) goto startio; @@ -2149,6 +2227,9 @@ queue: full: blk_stop_queue(q); startio: + /* We will already have the driver lock here so not need + * to lock it. + */ start_io(h); } @@ -2158,7 +2239,8 @@ static irqreturn_t do_cciss_intr(int irq CommandList_struct *c; unsigned long flags; __u32 a, a1; - + int j; + int start_queue = h->next_to_run; /* Is this interrupt for us? */ if (( h->access.intr_pending(h) == 0) || (h->interrupts_enabled == 0)) @@ -2205,13 +2287,50 @@ static irqreturn_t do_cciss_intr(int irq } } - /* - * See if we can queue up some more IO + /* check to see if we have maxed out the number of commands that can + * be placed on the queue. If so then exit. We do this check here + * in case the interrupt we serviced was from an ioctl and did not + * free any new commands. */ - blk_start_queue(h->queue); + if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) + goto cleanup; + + /* We have room on the queue for more commands. Now we need to queue + * them up. We will also keep track of the next queue to run so + * that every queue gets a chance to be started first. + */ + for (j=0; j < NWD; j++){ + int curr_queue = (start_queue + j) % NWD; + /* make sure the disk has been added and the drive is real + * because this can be called from the middle of init_one. + */ + if(!(h->gendisk[curr_queue]->queue) || + !(h->drv[curr_queue].heads)) + continue; + blk_start_queue(h->gendisk[curr_queue]->queue); + + /* check to see if we have maxed out the number of commands + * that can be placed on the queue. + */ + if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) + { + if (curr_queue == start_queue){ + h->next_to_run = (start_queue + 1) % NWD; + goto cleanup; + } else { + h->next_to_run = curr_queue; + goto cleanup; + } + } else { + curr_queue = (curr_queue + 1) % NWD; + } + } + +cleanup: spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); return IRQ_HANDLED; } + /* * We cannot read the structure directly, for portablity we must use * the io functions. @@ -2300,7 +2419,6 @@ static int find_PCI_BAR_index(struct pci static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) { ushort subsystem_vendor_id, subsystem_device_id, command; - unchar irq = pdev->irq; __u32 board_id, scratchpad = 0; __u64 cfg_offset; __u32 cfg_base_addr; @@ -2359,11 +2477,11 @@ static int cciss_pci_init(ctlr_info_t *c #ifdef CCISS_DEBUG printk("command = %x\n", command); - printk("irq = %x\n", irq); + printk("irq = %x\n", pdev->irq); printk("board_id = %x\n", board_id); #endif /* CCISS_DEBUG */ - c->intr = irq; + c->intr = pdev->irq; /* * Memory base addr is first addr , the second points to the config @@ -2411,9 +2529,9 @@ static int cciss_pci_init(ctlr_info_t *c #ifdef CCISS_DEBUG printk("cfg offset = %x\n", cfg_offset); #endif /* CCISS_DEBUG */ - c->cfgtable = (CfgTable_struct *) - remap_pci_mem(pci_resource_start(pdev, cfg_base_addr_index) - + cfg_offset, sizeof(CfgTable_struct)); + c->cfgtable = remap_pci_mem(pci_resource_start(pdev, + cfg_base_addr_index) + cfg_offset, + sizeof(CfgTable_struct)); c->board_id = board_id; #ifdef CCISS_DEBUG @@ -2626,7 +2744,7 @@ static int alloc_cciss_hba(void) } } printk(KERN_WARNING "cciss: This driver supports a maximum" - " of 8 controllers.\n"); + " of %d controllers.\n", MAX_CTLR); goto out; Enomem: printk(KERN_ERR "cciss: out of memory.\n"); @@ -2658,13 +2776,14 @@ static int __devinit cciss_init_one(stru request_queue_t *q; int i; int j; + int rc; 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 ) + if(i < 0) return (-1); if (cciss_pci_init(hba[i], pdev) != 0) goto clean1; @@ -2683,11 +2802,24 @@ static int __devinit cciss_init_one(stru goto clean1; } - if (register_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname)) { - printk(KERN_ERR "cciss: Unable to register device %s\n", - hba[i]->devname); + /* + * register with the major number, or get a dynamic major number + * by passing 0 as argument. This is done for greater than + * 8 controller support. + */ + if (i < MAX_CTLR_ORIG) + hba[i]->major = MAJOR_NR + i; + rc = register_blkdev(hba[i]->major, hba[i]->devname); + if(rc == -EBUSY || rc == -EINVAL) { + printk(KERN_ERR + "cciss: Unable to get major number %d for %s " + "on hba %d\n", hba[i]->major, hba[i]->devname, i); goto clean1; } + else { + if (i >= MAX_CTLR_ORIG) + hba[i]->major = rc; + } /* make sure the board interrupts are off */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); @@ -2758,12 +2890,14 @@ static int __devinit cciss_init_one(stru sprintf(disk->disk_name, "cciss/c%dd%d", i, j); sprintf(disk->devfs_name, "cciss/host%d/target%d", i, j); - disk->major = COMPAQ_CISS_MAJOR + i; + disk->major = hba[i]->major; disk->first_minor = j << NWD_SHIFT; disk->fops = &cciss_fops; disk->queue = hba[i]->queue; disk->private_data = drv; - if( !(drv->nr_blocks)) + /* we must register the controller even if no disks exist */ + /* this is for the online array utilities */ + if(!drv->heads && j) continue; blk_queue_hardsect_size(hba[i]->queue, drv->block_size); set_capacity(disk, drv->nr_blocks); @@ -2785,7 +2919,7 @@ clean4: hba[i]->errinfo_pool_dhandle); free_irq(hba[i]->intr, hba[i]); clean2: - unregister_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname); + unregister_blkdev(hba[i]->major, hba[i]->devname); clean1: release_io_mem(hba[i]); free_hba(i); @@ -2825,9 +2959,9 @@ static void __devexit cciss_remove_one ( } free_irq(hba[i]->intr, hba[i]); pci_set_drvdata(pdev, NULL); - iounmap((void*)hba[i]->vaddr); + iounmap(hba[i]->vaddr); cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ - unregister_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname); + unregister_blkdev(hba[i]->major, hba[i]->devname); remove_proc_entry(hba[i]->devname, proc_cciss); /* remove it from the disk list */ --- linux-2.6.8.1-t047-cciss/drivers/block/cciss.h 2005-11-22 18:01:33.205086568 +0300 +++ rhel4u2/drivers/block/cciss.h 2005-10-19 11:47:13.000000000 +0400 @@ -13,6 +13,8 @@ #define IO_OK 0 #define IO_ERROR 1 +#define MAJOR_NR COMPAQ_CISS_MAJOR + struct ctlr_info; typedef struct ctlr_info ctlr_info_t; @@ -43,13 +45,14 @@ struct ctlr_info char firm_ver[4]; // Firmware version struct pci_dev *pdev; __u32 board_id; - unsigned long vaddr; + void __iomem *vaddr; unsigned long paddr; unsigned long io_mem_addr; unsigned long io_mem_length; - CfgTable_struct *cfgtable; - int intr; + CfgTable_struct __iomem *cfgtable; + unsigned int intr; int interrupts_enabled; + int major; int max_commands; int commands_outstanding; int max_outstanding; /* Debug */ @@ -81,6 +84,11 @@ struct ctlr_info int nr_frees; int busy_configuring; + /* This element holds the zero based queue number of the last + * queue to be started. It is used for fairness. + */ + int next_to_run; + // Disk structures we need to pass back struct gendisk *gendisk[NWD]; #ifdef CONFIG_CISS_SCSI_TAPE --- linux-2.6.8.1-t047-cciss/drivers/block/cciss_scsi.c 2005-11-22 18:01:33.206086416 +0300 +++ rhel4u2/drivers/block/cciss_scsi.c 2005-10-19 11:47:13.000000000 +0400 @@ -696,6 +696,7 @@ static int cciss_scsi_detect(int ctlr) { struct Scsi_Host *sh; + int error; sh = scsi_host_alloc(&cciss_driver_template, sizeof(struct ctlr_info *)); if (sh == NULL) @@ -711,10 +712,15 @@ cciss_scsi_detect(int ctlr) sh->hostdata[0] = (unsigned long) hba[ctlr]; sh->irq = hba[ctlr]->intr; sh->unique_id = sh->irq; - scsi_add_host(sh, &hba[ctlr]->pdev->dev); /* XXX handle failure */ + error = scsi_add_host(sh, &hba[ctlr]->pdev->dev); + if (error) + goto fail_host_put; scsi_scan_host(sh); - return 1; + +fail_host_put: + scsi_host_put(sh); + return 0; } static void __exit cleanup_cciss_module(void); --- linux-2.6.8.1-t047-cciss/include/linux/cciss_ioctl.h 2004-08-14 14:55:20.000000000 +0400 +++ rhel4u2/include/linux/cciss_ioctl.h 2005-10-19 11:47:13.000000000 +0400 @@ -11,6 +11,7 @@ typedef struct _cciss_pci_info_struct { unsigned char bus; unsigned char dev_fn; + unsigned short domain; __u32 board_id; } cciss_pci_info_struct;