X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fblock%2Fcciss.c;h=030e52d722545b8b3f069d0386a56094154b6836;hb=086fa5ff0854c676ec333760f4c0154b3b242616;hp=04036ef8ea5a206b2c850be6855ebfff65016e43;hpb=9cef0d2f4f68a5a2c6ea0495f958a074d21fbd07;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 04036ef..030e52d 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -68,6 +68,12 @@ MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" MODULE_VERSION("3.6.20"); MODULE_LICENSE("GPL"); +static int cciss_allow_hpsa; +module_param(cciss_allow_hpsa, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(cciss_allow_hpsa, + "Prevent cciss driver from accessing hardware known to be " + " supported by the hpsa driver"); + #include "cciss_cmd.h" #include "cciss.h" #include @@ -101,8 +107,6 @@ static const struct pci_device_id cciss_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324A}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324B}, - {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, {0,} }; @@ -123,8 +127,6 @@ static struct board_type products[] = { {0x409D0E11, "Smart Array 6400 EM", &SA5_access}, {0x40910E11, "Smart Array 6i", &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}, @@ -132,6 +134,10 @@ static struct board_type products[] = { {0x3214103C, "Smart Array E200i", &SA5_access}, {0x3215103C, "Smart Array E200i", &SA5_access}, {0x3237103C, "Smart Array E500", &SA5_access}, +/* controllers below this line are also supported by the hpsa driver. */ +#define HPSA_BOUNDARY 0x3223103C + {0x3223103C, "Smart Array P800", &SA5_access}, + {0x3234103C, "Smart Array P400", &SA5_access}, {0x323D103C, "Smart Array P700m", &SA5_access}, {0x3241103C, "Smart Array P212", &SA5_access}, {0x3243103C, "Smart Array P410", &SA5_access}, @@ -140,7 +146,6 @@ static struct board_type products[] = { {0x3249103C, "Smart Array P812", &SA5_access}, {0x324A103C, "Smart Array P712m", &SA5_access}, {0x324B103C, "Smart Array P711m", &SA5_access}, - {0xFFFF103C, "Unknown Smart Array", &SA5_access}, }; /* How long to wait (in milliseconds) for board to go into simple mode */ @@ -174,19 +179,17 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time, int via_ioctl); static int deregister_disk(ctlr_info_t *h, int drv_index, int clear_all, int via_ioctl); -static void cciss_read_capacity(int ctlr, int logvol, int withirq, +static void cciss_read_capacity(int ctlr, int logvol, sector_t *total_size, unsigned int *block_size); -static void cciss_read_capacity_16(int ctlr, int logvol, int withirq, +static void cciss_read_capacity_16(int ctlr, int logvol, sector_t *total_size, unsigned int *block_size); static void cciss_geometry_inquiry(int ctlr, int logvol, - int withirq, sector_t total_size, + sector_t total_size, unsigned int block_size, InquiryData_struct *inq_buff, drive_info_struct *drv); static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32); static void start_io(ctlr_info_t *h); -static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, - __u8 page_code, unsigned char *scsi3addr, int cmd_type); static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, __u8 page_code, unsigned char scsi3addr[], int cmd_type); @@ -256,6 +259,11 @@ static inline void removeQ(CommandList_struct *c) #include "cciss_scsi.c" /* For SCSI tape support */ +static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", + "UNKNOWN" +}; +#define RAID_UNKNOWN (sizeof(raid_label) / sizeof(raid_label[0])-1) + #ifdef CONFIG_PROC_FS /* @@ -264,10 +272,6 @@ static inline void removeQ(CommandList_struct *c) #define ENG_GIG 1000000000 #define ENG_GIG_FACTOR (ENG_GIG/512) #define ENGAGE_SCSI "engage scsi" -static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", - "UNKNOWN" -}; -#define RAID_UNKNOWN (sizeof(raid_label) / sizeof(raid_label[0])-1) static struct proc_dir_entry *proc_cciss; @@ -333,6 +337,9 @@ static int cciss_seq_show(struct seq_file *seq, void *v) if (*pos > h->highest_lun) return 0; + if (drv == NULL) /* it's possible for h->drv[] to have holes. */ + return 0; + if (drv->heads == 0) return 0; @@ -418,12 +425,9 @@ cciss_proc_write(struct file *file, const char __user *buf, if (strncmp(ENGAGE_SCSI, buffer, sizeof ENGAGE_SCSI - 1) == 0) { struct seq_file *seq = file->private_data; ctlr_info_t *h = seq->private; - int rc; - rc = cciss_engage_scsi(h->ctlr); - if (rc != 0) - err = -rc; - else + err = cciss_engage_scsi(h->ctlr); + if (err == 0) err = length; } else #endif /* CONFIG_CISS_SCSI_TAPE */ @@ -436,7 +440,7 @@ out: return err; } -static struct file_operations cciss_proc_fops = { +static const struct file_operations cciss_proc_fops = { .owner = THIS_MODULE, .open = cciss_seq_open, .read = seq_read, @@ -476,7 +480,7 @@ static ssize_t host_store_rescan(struct device *dev, return count; } -DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan); +static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan); static ssize_t dev_show_unique_id(struct device *dev, struct device_attribute *attr, @@ -506,7 +510,7 @@ static ssize_t dev_show_unique_id(struct device *dev, sn[8], sn[9], sn[10], sn[11], sn[12], sn[13], sn[14], sn[15]); } -DEVICE_ATTR(unique_id, S_IRUGO, dev_show_unique_id, NULL); +static DEVICE_ATTR(unique_id, S_IRUGO, dev_show_unique_id, NULL); static ssize_t dev_show_vendor(struct device *dev, struct device_attribute *attr, @@ -530,7 +534,7 @@ static ssize_t dev_show_vendor(struct device *dev, else return snprintf(buf, sizeof(vendor) + 1, "%s\n", drv->vendor); } -DEVICE_ATTR(vendor, S_IRUGO, dev_show_vendor, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, dev_show_vendor, NULL); static ssize_t dev_show_model(struct device *dev, struct device_attribute *attr, @@ -554,7 +558,7 @@ static ssize_t dev_show_model(struct device *dev, else return snprintf(buf, sizeof(model) + 1, "%s\n", drv->model); } -DEVICE_ATTR(model, S_IRUGO, dev_show_model, NULL); +static DEVICE_ATTR(model, S_IRUGO, dev_show_model, NULL); static ssize_t dev_show_rev(struct device *dev, struct device_attribute *attr, @@ -578,7 +582,7 @@ static ssize_t dev_show_rev(struct device *dev, else return snprintf(buf, sizeof(rev) + 1, "%s\n", drv->rev); } -DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL); +static DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL); static ssize_t cciss_show_lunid(struct device *dev, struct device_attribute *attr, char *buf) @@ -603,7 +607,7 @@ static ssize_t cciss_show_lunid(struct device *dev, lunid[0], lunid[1], lunid[2], lunid[3], lunid[4], lunid[5], lunid[6], lunid[7]); } -DEVICE_ATTR(lunid, S_IRUGO, cciss_show_lunid, NULL); +static DEVICE_ATTR(lunid, S_IRUGO, cciss_show_lunid, NULL); static ssize_t cciss_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf) @@ -626,7 +630,7 @@ static ssize_t cciss_show_raid_level(struct device *dev, return snprintf(buf, strlen(raid_label[raid]) + 7, "RAID %s\n", raid_label[raid]); } -DEVICE_ATTR(raid_level, S_IRUGO, cciss_show_raid_level, NULL); +static DEVICE_ATTR(raid_level, S_IRUGO, cciss_show_raid_level, NULL); static ssize_t cciss_show_usage_count(struct device *dev, struct device_attribute *attr, char *buf) @@ -645,7 +649,7 @@ static ssize_t cciss_show_usage_count(struct device *dev, spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); return snprintf(buf, 20, "%d\n", count); } -DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL); +static DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL); static struct attribute *cciss_host_attrs[] = { &dev_attr_rescan.attr, @@ -656,7 +660,7 @@ static struct attribute_group cciss_host_attr_group = { .attrs = cciss_host_attrs, }; -static struct attribute_group *cciss_host_attr_groups[] = { +static const struct attribute_group *cciss_host_attr_groups[] = { &cciss_host_attr_group, NULL }; @@ -1340,26 +1344,27 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, kfree(buff); return -ENOMEM; } - // Fill in the command type + /* Fill in the command type */ c->cmd_type = CMD_IOCTL_PEND; - // Fill in Command Header - c->Header.ReplyQueue = 0; // unused in simple mode - if (iocommand.buf_size > 0) // buffer to fill + /* Fill in Command Header */ + c->Header.ReplyQueue = 0; /* unused in simple mode */ + if (iocommand.buf_size > 0) /* buffer to fill */ { c->Header.SGList = 1; c->Header.SGTotal = 1; - } else // no buffers to fill + } else /* no buffers to fill */ { c->Header.SGList = 0; c->Header.SGTotal = 0; } c->Header.LUN = iocommand.LUN_info; - c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag + /* use the kernel address the cmd block for tag */ + c->Header.Tag.lower = c->busaddr; - // Fill in Request block + /* Fill in Request block */ c->Request = iocommand.Request; - // Fill in the scatter gather information + /* Fill in the scatter gather information */ if (iocommand.buf_size > 0) { temp64.val = pci_map_single(host->pdev, buff, iocommand.buf_size, @@ -1367,7 +1372,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, c->SG[0].Addr.lower = temp64.val32.lower; c->SG[0].Addr.upper = temp64.val32.upper; c->SG[0].Len = iocommand.buf_size; - c->SG[0].Ext = 0; // we are not chaining + c->SG[0].Ext = 0; /* we are not chaining */ } c->waiting = &wait; @@ -1651,9 +1656,11 @@ static void cciss_softirq_done(struct request *rq) { CommandList_struct *cmd = rq->completion_data; ctlr_info_t *h = hba[cmd->ctlr]; + SGDescriptor_struct *curr_sg = cmd->SG; unsigned long flags; u64bit temp64; int i, ddir; + int sg_index = 0; if (cmd->Request.Type.Direction == XFER_READ) ddir = PCI_DMA_FROMDEVICE; @@ -1663,9 +1670,22 @@ static void cciss_softirq_done(struct request *rq) /* command did not need to be retried */ /* 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_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); + if (curr_sg[sg_index].Ext == CCISS_SG_CHAIN) { + temp64.val32.lower = cmd->SG[i].Addr.lower; + temp64.val32.upper = cmd->SG[i].Addr.upper; + pci_dma_sync_single_for_cpu(h->pdev, temp64.val, + cmd->SG[i].Len, ddir); + pci_unmap_single(h->pdev, temp64.val, + cmd->SG[i].Len, ddir); + /* Point to the next block */ + curr_sg = h->cmd_sg_list[cmd->cmdindex]->sgchain; + sg_index = 0; + } + temp64.val32.lower = curr_sg[sg_index].Addr.lower; + temp64.val32.upper = curr_sg[sg_index].Addr.upper; + pci_unmap_page(h->pdev, temp64.val, curr_sg[sg_index].Len, + ddir); + ++sg_index; } #ifdef CCISS_DEBUG @@ -1695,7 +1715,7 @@ static inline void log_unit_to_scsi3addr(ctlr_info_t *h, * via the inquiry page 0. Model, vendor, and rev are set to empty strings if * they cannot be read. */ -static void cciss_get_device_descr(int ctlr, int logvol, int withirq, +static void cciss_get_device_descr(int ctlr, int logvol, char *vendor, char *model, char *rev) { int rc; @@ -1711,14 +1731,8 @@ static void cciss_get_device_descr(int ctlr, int logvol, int withirq, return; log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); - if (withirq) - rc = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buf, - sizeof(InquiryData_struct), 0, - scsi3addr, TYPE_CMD); - else - rc = sendcmd(CISS_INQUIRY, ctlr, inq_buf, - sizeof(InquiryData_struct), 0, - scsi3addr, TYPE_CMD); + rc = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buf, sizeof(*inq_buf), 0, + scsi3addr, TYPE_CMD); if (rc == IO_OK) { memcpy(vendor, &inq_buf->data_byte[8], VENDOR_LEN); vendor[VENDOR_LEN] = '\0'; @@ -1737,7 +1751,7 @@ static void cciss_get_device_descr(int ctlr, int logvol, int withirq, * number cannot be had, for whatever reason, 16 bytes of 0xff * are returned instead. */ -static void cciss_get_serial_no(int ctlr, int logvol, int withirq, +static void cciss_get_serial_no(int ctlr, int logvol, unsigned char *serial_no, int buflen) { #define PAGE_83_INQ_BYTES 64 @@ -1753,12 +1767,8 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq, return; memset(serial_no, 0, buflen); log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); - if (withirq) - rc = sendcmd_withirq(CISS_INQUIRY, ctlr, buf, - PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD); - else - rc = sendcmd(CISS_INQUIRY, ctlr, buf, - PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD); + rc = sendcmd_withirq(CISS_INQUIRY, ctlr, buf, + PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD); if (rc == IO_OK) memcpy(serial_no, &buf[8], buflen); kfree(buf); @@ -1787,12 +1797,12 @@ static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk, blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask); /* This is a hardware imposed limit. */ - blk_queue_max_hw_segments(disk->queue, MAXSGENTRIES); + blk_queue_max_hw_segments(disk->queue, h->maxsgentries); /* This is a limit in the driver and could be eliminated. */ - blk_queue_max_phys_segments(disk->queue, MAXSGENTRIES); + blk_queue_max_phys_segments(disk->queue, h->maxsgentries); - blk_queue_max_sectors(disk->queue, h->cciss_max_sectors); + blk_queue_max_hw_sectors(disk->queue, h->cciss_max_sectors); blk_queue_softirq_done(disk->queue, cciss_softirq_done); @@ -1846,18 +1856,16 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time, /* testing to see if 16-byte CDBs are already being used */ if (h->cciss_read == CCISS_READ_16) { - cciss_read_capacity_16(h->ctlr, drv_index, 1, + cciss_read_capacity_16(h->ctlr, drv_index, &total_size, &block_size); } else { - cciss_read_capacity(ctlr, drv_index, 1, - &total_size, &block_size); - + cciss_read_capacity(ctlr, drv_index, &total_size, &block_size); /* if read_capacity returns all F's this volume is >2TB */ /* in size so we switch to 16-byte CDB's for all */ /* read/write ops */ if (total_size == 0xFFFFFFFFULL) { - cciss_read_capacity_16(ctlr, drv_index, 1, + cciss_read_capacity_16(ctlr, drv_index, &total_size, &block_size); h->cciss_read = CCISS_READ_16; h->cciss_write = CCISS_WRITE_16; @@ -1867,14 +1875,14 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time, } } - cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size, + cciss_geometry_inquiry(ctlr, drv_index, total_size, block_size, inq_buff, drvinfo); drvinfo->block_size = block_size; drvinfo->nr_blocks = total_size + 1; - cciss_get_device_descr(ctlr, drv_index, 1, drvinfo->vendor, + cciss_get_device_descr(ctlr, drv_index, drvinfo->vendor, drvinfo->model, drvinfo->rev); - cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no, + cciss_get_serial_no(ctlr, drv_index, drvinfo->serial_no, sizeof(drvinfo->serial_no)); /* Save the lunid in case we deregister the disk, below. */ memcpy(drvinfo->LunID, h->drv[drv_index]->LunID, @@ -2418,7 +2426,7 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, 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[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; @@ -2525,6 +2533,8 @@ static int check_target_status(ctlr_info_t *h, CommandList_struct *c) case 0: return IO_OK; /* no sense */ case 1: return IO_OK; /* recovered error */ default: + if (check_for_unit_attention(h, c)) + return IO_NEEDS_RETRY; printk(KERN_WARNING "cciss%d: cmd 0x%02x " "check condition, sense key = 0x%02x\n", h->ctlr, c->Request.CDB[0], @@ -2666,7 +2676,7 @@ static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, } static void cciss_geometry_inquiry(int ctlr, int logvol, - int withirq, sector_t total_size, + sector_t total_size, unsigned int block_size, InquiryData_struct *inq_buff, drive_info_struct *drv) @@ -2677,21 +2687,15 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, memset(inq_buff, 0, sizeof(InquiryData_struct)); log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); - if (withirq) - return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, - inq_buff, sizeof(*inq_buff), - 0xC1, scsi3addr, TYPE_CMD); - else - return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff, - sizeof(*inq_buff), 0xC1, scsi3addr, - TYPE_CMD); + return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff, + sizeof(*inq_buff), 0xC1, scsi3addr, TYPE_CMD); if (return_code == IO_OK) { if (inq_buff->data_byte[8] == 0xFF) { printk(KERN_WARNING "cciss: reading geometry failed, volume " "does not support reading geometry\n"); drv->heads = 255; - drv->sectors = 32; // Sectors per track + drv->sectors = 32; /* Sectors per track */ drv->cylinders = total_size + 1; drv->raid_level = RAID_UNKNOWN; } else { @@ -2717,7 +2721,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, } static void -cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, +cciss_read_capacity(int ctlr, int logvol, sector_t *total_size, unsigned int *block_size) { ReadCapdata_struct *buf; @@ -2731,14 +2735,8 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, } log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); - if (withirq) - return_code = sendcmd_withirq(CCISS_READ_CAPACITY, - ctlr, buf, sizeof(ReadCapdata_struct), - 0, scsi3addr, TYPE_CMD); - else - return_code = sendcmd(CCISS_READ_CAPACITY, - ctlr, buf, sizeof(ReadCapdata_struct), - 0, scsi3addr, TYPE_CMD); + return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, buf, + sizeof(ReadCapdata_struct), 0, scsi3addr, TYPE_CMD); if (return_code == IO_OK) { *total_size = be32_to_cpu(*(__be32 *) buf->total_size); *block_size = be32_to_cpu(*(__be32 *) buf->block_size); @@ -2750,8 +2748,8 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, kfree(buf); } -static void -cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, unsigned int *block_size) +static void cciss_read_capacity_16(int ctlr, int logvol, + sector_t *total_size, unsigned int *block_size) { ReadCapdata_struct_16 *buf; int return_code; @@ -2764,16 +2762,9 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, } log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); - if (withirq) { - return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16, - ctlr, buf, sizeof(ReadCapdata_struct_16), - 0, scsi3addr, TYPE_CMD); - } - else { - return_code = sendcmd(CCISS_READ_CAPACITY_16, - ctlr, buf, sizeof(ReadCapdata_struct_16), - 0, scsi3addr, TYPE_CMD); - } + return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16, + ctlr, buf, sizeof(ReadCapdata_struct_16), + 0, scsi3addr, TYPE_CMD); if (return_code == IO_OK) { *total_size = be64_to_cpu(*(__be64 *) buf->total_size); *block_size = be32_to_cpu(*(__be32 *) buf->block_size); @@ -2814,13 +2805,13 @@ static int cciss_revalidate(struct gendisk *disk) return 1; } if (h->cciss_read == CCISS_READ_10) { - cciss_read_capacity(h->ctlr, logvol, 1, + cciss_read_capacity(h->ctlr, logvol, &total_size, &block_size); } else { - cciss_read_capacity_16(h->ctlr, logvol, 1, + cciss_read_capacity_16(h->ctlr, logvol, &total_size, &block_size); } - cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, + cciss_geometry_inquiry(h->ctlr, logvol, total_size, block_size, inq_buff, drv); blk_queue_logical_block_size(drv->queue, drv->block_size); @@ -2831,167 +2822,6 @@ static int cciss_revalidate(struct gendisk *disk) } /* - * Wait polling for a command to complete. - * The memory mapped FIFO is polled for the completion. - * Used only at init time, interrupts from the HBA are disabled. - */ -static unsigned long pollcomplete(int ctlr) -{ - unsigned long done; - int i; - - /* Wait (up to 20 seconds) for a command to complete */ - - for (i = 20 * HZ; i > 0; i--) { - done = hba[ctlr]->access.command_completed(hba[ctlr]); - if (done == FIFO_EMPTY) - schedule_timeout_uninterruptible(1); - else - return done; - } - /* Invalid address to tell caller we ran out of time */ - return 1; -} - -/* Send command c to controller h and poll for it to complete. - * Turns interrupts off on the board. Used at driver init time - * and during SCSI error recovery. - */ -static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c) -{ - int i; - unsigned long complete; - int status = IO_ERROR; - u64bit buff_dma_handle; - -resend_cmd1: - - /* Disable interrupt on the board. */ - h->access.set_intr_mask(h, CCISS_INTR_OFF); - - /* Make sure there is room in the command FIFO */ - /* Actually it should be completely empty at this time */ - /* unless we are in here doing error handling for the scsi */ - /* tape side of the driver. */ - for (i = 200000; i > 0; i--) { - /* if fifo isn't full go */ - if (!(h->access.fifo_full(h))) - break; - udelay(10); - printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full," - " waiting!\n", h->ctlr); - } - h->access.submit_command(h, c); /* Send the cmd */ - do { - complete = pollcomplete(h->ctlr); - -#ifdef CCISS_DEBUG - printk(KERN_DEBUG "cciss: command completed\n"); -#endif /* CCISS_DEBUG */ - - if (complete == 1) { - printk(KERN_WARNING - "cciss cciss%d: SendCmd Timeout out, " - "No command list address returned!\n", h->ctlr); - status = IO_ERROR; - break; - } - - /* Make sure it's the command we're expecting. */ - if ((complete & ~CISS_ERROR_BIT) != c->busaddr) { - printk(KERN_WARNING "cciss%d: Unexpected command " - "completion.\n", h->ctlr); - continue; - } - - /* It is our command. If no error, we're done. */ - if (!(complete & CISS_ERROR_BIT)) { - status = IO_OK; - break; - } - - /* There is an error... */ - - /* if data overrun or underun on Report command ignore it */ - if (((c->Request.CDB[0] == CISS_REPORT_LOG) || - (c->Request.CDB[0] == CISS_REPORT_PHYS) || - (c->Request.CDB[0] == CISS_INQUIRY)) && - ((c->err_info->CommandStatus == CMD_DATA_OVERRUN) || - (c->err_info->CommandStatus == CMD_DATA_UNDERRUN))) { - complete = c->busaddr; - status = IO_OK; - break; - } - - if (c->err_info->CommandStatus == CMD_UNSOLICITED_ABORT) { - printk(KERN_WARNING "cciss%d: unsolicited abort %p\n", - h->ctlr, c); - if (c->retry_count < MAX_CMD_RETRIES) { - printk(KERN_WARNING "cciss%d: retrying %p\n", - h->ctlr, c); - c->retry_count++; - /* erase the old error information */ - memset(c->err_info, 0, sizeof(c->err_info)); - goto resend_cmd1; - } - printk(KERN_WARNING "cciss%d: retried %p too many " - "times\n", h->ctlr, c); - status = IO_ERROR; - break; - } - - if (c->err_info->CommandStatus == CMD_UNABORTABLE) { - printk(KERN_WARNING "cciss%d: command could not be " - "aborted.\n", h->ctlr); - status = IO_ERROR; - break; - } - - if (c->err_info->CommandStatus == CMD_TARGET_STATUS) { - status = check_target_status(h, c); - break; - } - - printk(KERN_WARNING "cciss%d: sendcmd error\n", h->ctlr); - printk(KERN_WARNING "cmd = 0x%02x, CommandStatus = 0x%02x\n", - c->Request.CDB[0], c->err_info->CommandStatus); - status = IO_ERROR; - break; - - } while (1); - - /* unlock the data buffer from DMA */ - buff_dma_handle.val32.lower = c->SG[0].Addr.lower; - buff_dma_handle.val32.upper = c->SG[0].Addr.upper; - pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val, - c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); - return status; -} - -/* - * Send a command to the controller, and wait for it to complete. - * Used at init time, and during SCSI error recovery. - */ -static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, - __u8 page_code, unsigned char *scsi3addr, int cmd_type) -{ - CommandList_struct *c; - int status; - - c = cmd_alloc(hba[ctlr], 1); - if (!c) { - printk(KERN_WARNING "cciss: unable to get memory"); - return IO_ERROR; - } - status = fill_cmd(c, cmd, ctlr, buff, size, page_code, - scsi3addr, cmd_type); - if (status == IO_OK) - status = sendcmd_core(hba[ctlr], c); - cmd_free(hba[ctlr], c, 1); - return status; -} - -/* * Map (physical) PCI mem into (virtual) kernel space */ static void __iomem *remap_pci_mem(ulong base, ulong size) @@ -3249,9 +3079,13 @@ static void do_cciss_request(struct request_queue *q) int seg; struct request *creq; u64bit temp64; - struct scatterlist tmp_sg[MAXSGENTRIES]; + struct scatterlist *tmp_sg; + SGDescriptor_struct *curr_sg; drive_info_struct *drv; int i, dir; + int nseg = 0; + int sg_index = 0; + int chained = 0; /* We call start_io here in case there is a command waiting on the * queue that has not been sent. @@ -3264,13 +3098,14 @@ static void do_cciss_request(struct request_queue *q) if (!creq) goto startio; - BUG_ON(creq->nr_phys_segments > MAXSGENTRIES); + BUG_ON(creq->nr_phys_segments > h->maxsgentries); if ((c = cmd_alloc(h, 1)) == NULL) goto full; blk_start_request(creq); + tmp_sg = h->scatter_list[c->cmdindex]; spin_unlock_irq(q->queue_lock); c->cmd_type = CMD_RWREQ; @@ -3278,19 +3113,19 @@ static void do_cciss_request(struct request_queue *q) /* fill in the request */ drv = creq->rq_disk->private_data; - c->Header.ReplyQueue = 0; // unused in simple mode + c->Header.ReplyQueue = 0; /* unused in simple mode */ /* got command from pool, so use the command block index instead */ /* for direct lookups. */ /* The first 2 bits are reserved for controller error reporting. */ c->Header.Tag.lower = (c->cmdindex << 3); c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */ memcpy(&c->Header.LUN, drv->LunID, sizeof(drv->LunID)); - c->Request.CDBLen = 10; // 12 byte commands not in FW yet; - c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.CDBLen = 10; /* 12 byte commands not in FW yet; */ + c->Request.Type.Type = TYPE_CMD; /* It is a command. */ c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE; - c->Request.Timeout = 0; // Don't time out + c->Request.Timeout = 0; /* Don't time out */ c->Request.CDB[0] = (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; start_blk = blk_rq_pos(creq); @@ -3299,7 +3134,7 @@ static void do_cciss_request(struct request_queue *q) (int)blk_rq_pos(creq), (int)blk_rq_sectors(creq)); #endif /* CCISS_DEBUG */ - sg_init_table(tmp_sg, MAXSGENTRIES); + sg_init_table(tmp_sg, h->maxsgentries); seg = blk_rq_map_sg(q, creq, tmp_sg); /* get the DMA records for the setup */ @@ -3308,33 +3143,78 @@ static void do_cciss_request(struct request_queue *q) else dir = PCI_DMA_TODEVICE; + curr_sg = c->SG; + sg_index = 0; + chained = 0; + for (i = 0; i < seg; i++) { - c->SG[i].Len = tmp_sg[i].length; + if (((sg_index+1) == (h->max_cmd_sgentries)) && + !chained && ((seg - i) > 1)) { + nseg = seg - i; + curr_sg[sg_index].Len = (nseg) * + sizeof(SGDescriptor_struct); + curr_sg[sg_index].Ext = CCISS_SG_CHAIN; + + /* Point to next chain block. */ + curr_sg = h->cmd_sg_list[c->cmdindex]->sgchain; + sg_index = 0; + chained = 1; + } + curr_sg[sg_index].Len = tmp_sg[i].length; temp64.val = (__u64) pci_map_page(h->pdev, sg_page(&tmp_sg[i]), - tmp_sg[i].offset, - tmp_sg[i].length, dir); - 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 + tmp_sg[i].offset, + tmp_sg[i].length, dir); + curr_sg[sg_index].Addr.lower = temp64.val32.lower; + curr_sg[sg_index].Addr.upper = temp64.val32.upper; + curr_sg[sg_index].Ext = 0; /* we are not chaining */ + + ++sg_index; } + + if (chained) { + int len; + curr_sg = c->SG; + sg_index = h->max_cmd_sgentries - 1; + len = curr_sg[sg_index].Len; + /* Setup pointer to next chain block. + * Fill out last element in current chain + * block with address of next chain block. + */ + temp64.val = pci_map_single(h->pdev, + h->cmd_sg_list[c->cmdindex]->sgchain, + len, dir); + + h->cmd_sg_list[c->cmdindex]->sg_chain_dma = temp64.val; + curr_sg[sg_index].Addr.lower = temp64.val32.lower; + curr_sg[sg_index].Addr.upper = temp64.val32.upper; + + pci_dma_sync_single_for_device(h->pdev, + h->cmd_sg_list[c->cmdindex]->sg_chain_dma, + len, dir); + } + /* track how many SG entries we are using */ if (seg > h->maxSG) h->maxSG = seg; #ifdef CCISS_DEBUG - printk(KERN_DEBUG "cciss: Submitting %u sectors in %d segments\n", - blk_rq_sectors(creq), seg); + printk(KERN_DEBUG "cciss: Submitting %ld sectors in %d segments " + "chained[%d]\n", + blk_rq_sectors(creq), seg, chained); #endif /* CCISS_DEBUG */ - c->Header.SGList = c->Header.SGTotal = seg; + c->Header.SGList = c->Header.SGTotal = seg + chained; + if (seg > h->max_cmd_sgentries) + c->Header.SGList = h->max_cmd_sgentries; + if (likely(blk_fs_request(creq))) { if(h->cciss_read == CCISS_READ_10) { c->Request.CDB[1] = 0; - c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB + c->Request.CDB[2] = (start_blk >> 24) & 0xff; /* MSB */ c->Request.CDB[3] = (start_blk >> 16) & 0xff; c->Request.CDB[4] = (start_blk >> 8) & 0xff; c->Request.CDB[5] = start_blk & 0xff; - c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB + c->Request.CDB[6] = 0; /* (sect >> 24) & 0xff; MSB */ c->Request.CDB[7] = (blk_rq_sectors(creq) >> 8) & 0xff; c->Request.CDB[8] = blk_rq_sectors(creq) & 0xff; c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; @@ -3343,7 +3223,7 @@ static void do_cciss_request(struct request_queue *q) c->Request.CDBLen = 16; c->Request.CDB[1]= 0; - c->Request.CDB[2]= (upper32 >> 24) & 0xff; //MSB + c->Request.CDB[2]= (upper32 >> 24) & 0xff; /* MSB */ c->Request.CDB[3]= (upper32 >> 16) & 0xff; c->Request.CDB[4]= (upper32 >> 8) & 0xff; c->Request.CDB[5]= upper32 & 0xff; @@ -3507,28 +3387,33 @@ static int add_to_scan_list(struct ctlr_info *h) * @h: Pointer to the controller. * * Removes the controller from the rescan queue if present. Blocks if - * the controller is currently conducting a rescan. + * the controller is currently conducting a rescan. The controller + * can be in one of three states: + * 1. Doesn't need a scan + * 2. On the scan list, but not scanning yet (we remove it) + * 3. Busy scanning (and not on the list). In this case we want to wait for + * the scan to complete to make sure the scanning thread for this + * controller is completely idle. **/ static void remove_from_scan_list(struct ctlr_info *h) { struct ctlr_info *test_h, *tmp_h; - int scanning = 0; mutex_lock(&scan_mutex); list_for_each_entry_safe(test_h, tmp_h, &scan_q, scan_list) { - if (test_h == h) { + if (test_h == h) { /* state 2. */ list_del(&h->scan_list); complete_all(&h->scan_wait); mutex_unlock(&scan_mutex); return; } } - if (&h->busy_scanning) - scanning = 0; - mutex_unlock(&scan_mutex); - - if (scanning) + if (h->busy_scanning) { /* state 3. */ + mutex_unlock(&scan_mutex); wait_for_completion(&h->scan_wait); + } else { /* state 1, nothing to do. */ + mutex_unlock(&scan_mutex); + } } /** @@ -3567,13 +3452,11 @@ static int scan_thread(void *data) h->busy_scanning = 1; mutex_unlock(&scan_mutex); - if (h) { - rebuild_lun_table(h, 0, 0); - complete_all(&h->scan_wait); - mutex_lock(&scan_mutex); - h->busy_scanning = 0; - mutex_unlock(&scan_mutex); - } + rebuild_lun_table(h, 0, 0); + complete_all(&h->scan_wait); + mutex_lock(&scan_mutex); + h->busy_scanning = 0; + mutex_unlock(&scan_mutex); } } @@ -3599,8 +3482,22 @@ static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c) case REPORT_LUNS_CHANGED: printk(KERN_WARNING "cciss%d: report LUN data " "changed\n", h->ctlr); - add_to_scan_list(h); - wake_up_process(cciss_scan_thread); + /* + * Here, we could call add_to_scan_list and wake up the scan thread, + * except that it's quite likely that we will get more than one + * REPORT_LUNS_CHANGED condition in quick succession, which means + * that those which occur after the first one will likely happen + * *during* the scan_thread's rescan. And the rescan code is not + * robust enough to restart in the middle, undoing what it has already + * done, and it's not clear that it's even possible to do this, since + * part of what it does is notify the block layer, which starts + * doing it's own i/o to read partition tables and so on, and the + * driver doesn't have visibility to know what might need undoing. + * In any event, if possible, it is horribly complicated to get right + * so we just don't do it for now. + * + * Note: this REPORT_LUNS_CHANGED condition only occurs on the MSA2012. + */ return 1; break; case POWER_OR_RESET: @@ -3753,7 +3650,27 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) __u64 cfg_offset; __u32 cfg_base_addr; __u64 cfg_base_addr_index; - int i, err; + int i, prod_index, err; + + subsystem_vendor_id = pdev->subsystem_vendor; + subsystem_device_id = pdev->subsystem_device; + board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) | + subsystem_vendor_id); + + for (i = 0; i < ARRAY_SIZE(products); i++) { + /* Stand aside for hpsa driver on request */ + if (cciss_allow_hpsa && products[i].board_id == HPSA_BOUNDARY) + return -ENODEV; + if (board_id == products[i].board_id) + break; + } + prod_index = i; + if (prod_index == ARRAY_SIZE(products)) { + dev_warn(&pdev->dev, + "unrecognized board ID: 0x%08lx, ignoring.\n", + (unsigned long) board_id); + return -ENODEV; + } /* check to see if controller has been disabled */ /* BEFORE trying to enable it */ @@ -3777,11 +3694,6 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) return err; } - subsystem_vendor_id = pdev->subsystem_vendor; - subsystem_device_id = pdev->subsystem_device; - board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) | - subsystem_vendor_id); - #ifdef CCISS_DEBUG printk("command = %x\n", command); printk("irq = %x\n", pdev->irq); @@ -3867,14 +3779,26 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) * leave a little room for ioctl calls. */ c->max_commands = readl(&(c->cfgtable->CmdsOutMax)); - for (i = 0; i < ARRAY_SIZE(products); i++) { - if (board_id == products[i].board_id) { - c->product_name = products[i].product_name; - c->access = *(products[i].access); - c->nr_cmds = c->max_commands - 4; - break; - } + c->maxsgentries = readl(&(c->cfgtable->MaxSGElements)); + + /* + * Limit native command to 32 s/g elements to save dma'able memory. + * Howvever spec says if 0, use 31 + */ + + c->max_cmd_sgentries = 31; + if (c->maxsgentries > 512) { + c->max_cmd_sgentries = 32; + c->chainsize = c->maxsgentries - c->max_cmd_sgentries + 1; + c->maxsgentries -= 1; /* account for chain pointer */ + } else { + c->maxsgentries = 31; /* Default to traditional value */ + c->chainsize = 0; /* traditional */ } + + c->product_name = products[prod_index].product_name; + c->access = *(products[prod_index].access); + c->nr_cmds = c->max_commands - 4; if ((readb(&c->cfgtable->Signature[0]) != 'C') || (readb(&c->cfgtable->Signature[1]) != 'I') || (readb(&c->cfgtable->Signature[2]) != 'S') || @@ -3883,27 +3807,6 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) err = -ENODEV; goto err_out_free_res; } - /* We didn't find the controller in our list. We know the - * signature is valid. If it's an HP device let's try to - * bind to the device and fire it up. Otherwise we bail. - */ - if (i == ARRAY_SIZE(products)) { - if (subsystem_vendor_id == PCI_VENDOR_ID_HP) { - c->product_name = products[i-1].product_name; - c->access = *(products[i-1].access); - c->nr_cmds = c->max_commands - 4; - printk(KERN_WARNING "cciss: This is an unknown " - "Smart Array controller.\n" - "cciss: Please update to the latest driver " - "available from www.hp.com.\n"); - } else { - printk(KERN_WARNING "cciss: Sorry, I don't know how" - " to access the Smart Array controller %08lx\n" - , (unsigned long)board_id); - err = -ENODEV; - goto err_out_free_res; - } - } #ifdef CONFIG_X86 { /* Need to enable prefetch in the SCSI core for 6400 in x86 */ @@ -4219,6 +4122,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, { int i; int j = 0; + int k = 0; int rc; int dac, return_code; InquiryData_struct *inq_buff; @@ -4253,7 +4157,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, mutex_init(&hba[i]->busy_shutting_down); if (cciss_pci_init(hba[i], pdev) != 0) - goto clean0; + goto clean_no_release_regions; sprintf(hba[i]->devname, "cciss%d", i); hba[i]->ctlr = i; @@ -4322,6 +4226,53 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, printk(KERN_ERR "cciss: out of memory"); goto clean4; } + + /* Need space for temp scatter list */ + hba[i]->scatter_list = kmalloc(hba[i]->max_commands * + sizeof(struct scatterlist *), + GFP_KERNEL); + for (k = 0; k < hba[i]->nr_cmds; k++) { + hba[i]->scatter_list[k] = kmalloc(sizeof(struct scatterlist) * + hba[i]->maxsgentries, + GFP_KERNEL); + if (hba[i]->scatter_list[k] == NULL) { + printk(KERN_ERR "cciss%d: could not allocate " + "s/g lists\n", i); + goto clean4; + } + } + hba[i]->cmd_sg_list = kmalloc(sizeof(struct Cmd_sg_list *) * + hba[i]->nr_cmds, + GFP_KERNEL); + if (!hba[i]->cmd_sg_list) { + printk(KERN_ERR "cciss%d: Cannot get memory for " + "s/g chaining.\n", i); + goto clean4; + } + /* Build up chain blocks for each command */ + if (hba[i]->chainsize > 0) { + for (j = 0; j < hba[i]->nr_cmds; j++) { + hba[i]->cmd_sg_list[j] = + kmalloc(sizeof(struct Cmd_sg_list), + GFP_KERNEL); + if (!hba[i]->cmd_sg_list[j]) { + printk(KERN_ERR "cciss%d: Cannot get memory " + "for chain block.\n", i); + goto clean4; + } + /* Need a block of chainsized s/g elements. */ + hba[i]->cmd_sg_list[j]->sgchain = + kmalloc((hba[i]->chainsize * + sizeof(SGDescriptor_struct)), + GFP_KERNEL); + if (!hba[i]->cmd_sg_list[j]->sgchain) { + printk(KERN_ERR "cciss%d: Cannot get memory " + "for s/g chains\n", i); + goto clean4; + } + } + } + spin_lock_init(&hba[i]->lock); /* Initialize the pdev driver private data. @@ -4367,7 +4318,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, cciss_procinit(i); - hba[i]->cciss_max_sectors = 2048; + hba[i]->cciss_max_sectors = 8192; rebuild_lun_table(hba[i], 1, 0); hba[i]->busy_initializing = 0; @@ -4375,6 +4326,20 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, clean4: kfree(hba[i]->cmd_pool_bits); + /* Free up sg elements */ + for (k = 0; k < hba[i]->nr_cmds; k++) + kfree(hba[i]->scatter_list[k]); + kfree(hba[i]->scatter_list); + /* Only free up extra s/g lists if controller supports them */ + if (hba[i]->chainsize > 0) { + for (j = 0; j < hba[i]->nr_cmds; j++) { + if (hba[i]->cmd_sg_list[j]) { + kfree(hba[i]->cmd_sg_list[j]->sgchain); + kfree(hba[i]->cmd_sg_list[j]); + } + } + kfree(hba[i]->cmd_sg_list); + } if (hba[i]->cmd_pool) pci_free_consistent(hba[i]->pdev, hba[i]->nr_cmds * sizeof(CommandList_struct), @@ -4390,13 +4355,14 @@ clean2: clean1: cciss_destroy_hba_sysfs_entry(hba[i]); clean0: + pci_release_regions(pdev); +clean_no_release_regions: hba[i]->busy_initializing = 0; /* * Deliberately omit pci_disable_device(): it does something nasty to * Smart Array controllers that pci_enable_device does not undo */ - pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); free_hba(i); return -1; @@ -4404,30 +4370,28 @@ clean0: static void cciss_shutdown(struct pci_dev *pdev) { - ctlr_info_t *tmp_ptr; - int i; - char flush_buf[4]; + ctlr_info_t *h; + char *flush_buf; int return_code; - tmp_ptr = pci_get_drvdata(pdev); - if (tmp_ptr == NULL) - return; - i = tmp_ptr->ctlr; - if (hba[i] == NULL) + h = pci_get_drvdata(pdev); + flush_buf = kzalloc(4, GFP_KERNEL); + if (!flush_buf) { + printk(KERN_WARNING + "cciss:%d cache not flushed, out of memory.\n", + h->ctlr); return; - - /* Turn board interrupts off and send the flush cache command */ - /* sendcmd will turn off interrupt, and send the flush... - * To write all data in the battery backed cache to disks */ - memset(flush_buf, 0, 4); - return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, - CTLR_LUNID, TYPE_CMD); - if (return_code == IO_OK) { - printk(KERN_INFO "Completed flushing cache on controller %d\n", i); - } else { - printk(KERN_WARNING "Error flushing cache on controller %d\n", i); } - free_irq(hba[i]->intr[2], hba[i]); + /* write all data in the battery backed cache to disk */ + memset(flush_buf, 0, 4); + return_code = sendcmd_withirq(CCISS_CACHE_FLUSH, h->ctlr, flush_buf, + 4, 0, CTLR_LUNID, TYPE_CMD); + kfree(flush_buf); + if (return_code != IO_OK) + printk(KERN_WARNING "cciss%d: Error flushing cache\n", + h->ctlr); + h->access.set_intr_mask(h, CCISS_INTR_OFF); + free_irq(h->intr[2], h); } static void __devexit cciss_remove_one(struct pci_dev *pdev) @@ -4489,6 +4453,20 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) pci_free_consistent(hba[i]->pdev, hba[i]->nr_cmds * sizeof(ErrorInfo_struct), hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle); kfree(hba[i]->cmd_pool_bits); + /* Free up sg elements */ + for (j = 0; j < hba[i]->nr_cmds; j++) + kfree(hba[i]->scatter_list[j]); + kfree(hba[i]->scatter_list); + /* Only free up extra s/g lists if controller supports them */ + if (hba[i]->chainsize > 0) { + for (j = 0; j < hba[i]->nr_cmds; j++) { + if (hba[i]->cmd_sg_list[j]) { + kfree(hba[i]->cmd_sg_list[j]->sgchain); + kfree(hba[i]->cmd_sg_list[j]); + } + } + kfree(hba[i]->cmd_sg_list); + } /* * Deliberately omit pci_disable_device(): it does something nasty to * Smart Array controllers that pci_enable_device does not undo