|
@@ -180,11 +180,13 @@ 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,
|
|
|
- unsigned int use_unit_num, unsigned int log_unit,
|
|
|
__u8 page_code, unsigned char *scsi3addr, int cmd_type);
|
|
|
static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
|
|
|
- unsigned int use_unit_num, unsigned int log_unit,
|
|
|
- __u8 page_code, int cmd_type);
|
|
|
+ __u8 page_code, unsigned char scsi3addr[],
|
|
|
+ int cmd_type);
|
|
|
+static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
|
|
|
+ int attempt_retry);
|
|
|
+static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c);
|
|
|
|
|
|
static void fail_all_cmds(unsigned long ctlr);
|
|
|
static int scan_thread(void *data);
|
|
@@ -437,6 +439,194 @@ static void __devinit cciss_procinit(int i)
|
|
|
}
|
|
|
#endif /* CONFIG_PROC_FS */
|
|
|
|
|
|
+#define MAX_PRODUCT_NAME_LEN 19
|
|
|
+
|
|
|
+#define to_hba(n) container_of(n, struct ctlr_info, dev)
|
|
|
+#define to_drv(n) container_of(n, drive_info_struct, dev)
|
|
|
+
|
|
|
+static struct device_type cciss_host_type = {
|
|
|
+ .name = "cciss_host",
|
|
|
+};
|
|
|
+
|
|
|
+static ssize_t dev_show_unique_id(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ drive_info_struct *drv = to_drv(dev);
|
|
|
+ struct ctlr_info *h = to_hba(drv->dev.parent);
|
|
|
+ __u8 sn[16];
|
|
|
+ unsigned long flags;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
|
|
|
+ if (h->busy_configuring)
|
|
|
+ ret = -EBUSY;
|
|
|
+ else
|
|
|
+ memcpy(sn, drv->serial_no, sizeof(sn));
|
|
|
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ else
|
|
|
+ return snprintf(buf, 16 * 2 + 2,
|
|
|
+ "%02X%02X%02X%02X%02X%02X%02X%02X"
|
|
|
+ "%02X%02X%02X%02X%02X%02X%02X%02X\n",
|
|
|
+ sn[0], sn[1], sn[2], sn[3],
|
|
|
+ sn[4], sn[5], sn[6], sn[7],
|
|
|
+ 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 ssize_t dev_show_vendor(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ drive_info_struct *drv = to_drv(dev);
|
|
|
+ struct ctlr_info *h = to_hba(drv->dev.parent);
|
|
|
+ char vendor[VENDOR_LEN + 1];
|
|
|
+ unsigned long flags;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
|
|
|
+ if (h->busy_configuring)
|
|
|
+ ret = -EBUSY;
|
|
|
+ else
|
|
|
+ memcpy(vendor, drv->vendor, VENDOR_LEN + 1);
|
|
|
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ else
|
|
|
+ return snprintf(buf, sizeof(vendor) + 1, "%s\n", drv->vendor);
|
|
|
+}
|
|
|
+DEVICE_ATTR(vendor, S_IRUGO, dev_show_vendor, NULL);
|
|
|
+
|
|
|
+static ssize_t dev_show_model(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ drive_info_struct *drv = to_drv(dev);
|
|
|
+ struct ctlr_info *h = to_hba(drv->dev.parent);
|
|
|
+ char model[MODEL_LEN + 1];
|
|
|
+ unsigned long flags;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
|
|
|
+ if (h->busy_configuring)
|
|
|
+ ret = -EBUSY;
|
|
|
+ else
|
|
|
+ memcpy(model, drv->model, MODEL_LEN + 1);
|
|
|
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ else
|
|
|
+ return snprintf(buf, sizeof(model) + 1, "%s\n", drv->model);
|
|
|
+}
|
|
|
+DEVICE_ATTR(model, S_IRUGO, dev_show_model, NULL);
|
|
|
+
|
|
|
+static ssize_t dev_show_rev(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ drive_info_struct *drv = to_drv(dev);
|
|
|
+ struct ctlr_info *h = to_hba(drv->dev.parent);
|
|
|
+ char rev[REV_LEN + 1];
|
|
|
+ unsigned long flags;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
|
|
|
+ if (h->busy_configuring)
|
|
|
+ ret = -EBUSY;
|
|
|
+ else
|
|
|
+ memcpy(rev, drv->rev, REV_LEN + 1);
|
|
|
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ else
|
|
|
+ return snprintf(buf, sizeof(rev) + 1, "%s\n", drv->rev);
|
|
|
+}
|
|
|
+DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL);
|
|
|
+
|
|
|
+static struct attribute *cciss_dev_attrs[] = {
|
|
|
+ &dev_attr_unique_id.attr,
|
|
|
+ &dev_attr_model.attr,
|
|
|
+ &dev_attr_vendor.attr,
|
|
|
+ &dev_attr_rev.attr,
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group cciss_dev_attr_group = {
|
|
|
+ .attrs = cciss_dev_attrs,
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group *cciss_dev_attr_groups[] = {
|
|
|
+ &cciss_dev_attr_group,
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+static struct device_type cciss_dev_type = {
|
|
|
+ .name = "cciss_device",
|
|
|
+ .groups = cciss_dev_attr_groups,
|
|
|
+};
|
|
|
+
|
|
|
+static struct bus_type cciss_bus_type = {
|
|
|
+ .name = "cciss",
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * Initialize sysfs entry for each controller. This sets up and registers
|
|
|
+ * the 'cciss#' directory for each individual controller under
|
|
|
+ * /sys/bus/pci/devices/<dev>/.
|
|
|
+ */
|
|
|
+static int cciss_create_hba_sysfs_entry(struct ctlr_info *h)
|
|
|
+{
|
|
|
+ device_initialize(&h->dev);
|
|
|
+ h->dev.type = &cciss_host_type;
|
|
|
+ h->dev.bus = &cciss_bus_type;
|
|
|
+ dev_set_name(&h->dev, "%s", h->devname);
|
|
|
+ h->dev.parent = &h->pdev->dev;
|
|
|
+
|
|
|
+ return device_add(&h->dev);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Remove sysfs entries for an hba.
|
|
|
+ */
|
|
|
+static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h)
|
|
|
+{
|
|
|
+ device_del(&h->dev);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Initialize sysfs for each logical drive. This sets up and registers
|
|
|
+ * the 'c#d#' directory for each individual logical drive under
|
|
|
+ * /sys/bus/pci/devices/<dev/ccis#/. We also create a link from
|
|
|
+ * /sys/block/cciss!c#d# to this entry.
|
|
|
+ */
|
|
|
+static int cciss_create_ld_sysfs_entry(struct ctlr_info *h,
|
|
|
+ drive_info_struct *drv,
|
|
|
+ int drv_index)
|
|
|
+{
|
|
|
+ device_initialize(&drv->dev);
|
|
|
+ drv->dev.type = &cciss_dev_type;
|
|
|
+ drv->dev.bus = &cciss_bus_type;
|
|
|
+ dev_set_name(&drv->dev, "c%dd%d", h->ctlr, drv_index);
|
|
|
+ drv->dev.parent = &h->dev;
|
|
|
+ return device_add(&drv->dev);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Remove sysfs entries for a logical drive.
|
|
|
+ */
|
|
|
+static void cciss_destroy_ld_sysfs_entry(drive_info_struct *drv)
|
|
|
+{
|
|
|
+ device_del(&drv->dev);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* 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
|
|
@@ -1299,7 +1489,6 @@ static void cciss_softirq_done(struct request *rq)
|
|
|
{
|
|
|
CommandList_struct *cmd = rq->completion_data;
|
|
|
ctlr_info_t *h = hba[cmd->ctlr];
|
|
|
- unsigned int nr_bytes;
|
|
|
unsigned long flags;
|
|
|
u64bit temp64;
|
|
|
int i, ddir;
|
|
@@ -1321,15 +1510,11 @@ static void cciss_softirq_done(struct request *rq)
|
|
|
printk("Done with %p\n", rq);
|
|
|
#endif /* CCISS_DEBUG */
|
|
|
|
|
|
- /*
|
|
|
- * Store the full size and set the residual count for pc requests
|
|
|
- */
|
|
|
- nr_bytes = blk_rq_bytes(rq);
|
|
|
+ /* set the residual count for pc requests */
|
|
|
if (blk_pc_request(rq))
|
|
|
- rq->data_len = cmd->err_info->ResidualCnt;
|
|
|
+ rq->resid_len = cmd->err_info->ResidualCnt;
|
|
|
|
|
|
- if (blk_end_request(rq, (rq->errors == 0) ? 0 : -EIO, nr_bytes))
|
|
|
- BUG();
|
|
|
+ blk_end_request_all(rq, (rq->errors == 0) ? 0 : -EIO);
|
|
|
|
|
|
spin_lock_irqsave(&h->lock, flags);
|
|
|
cmd_free(h, cmd, 1);
|
|
@@ -1337,6 +1522,56 @@ static void cciss_softirq_done(struct request *rq)
|
|
|
spin_unlock_irqrestore(&h->lock, flags);
|
|
|
}
|
|
|
|
|
|
+static void log_unit_to_scsi3addr(ctlr_info_t *h, unsigned char scsi3addr[],
|
|
|
+ uint32_t log_unit)
|
|
|
+{
|
|
|
+ log_unit = h->drv[log_unit].LunID & 0x03fff;
|
|
|
+ memset(&scsi3addr[4], 0, 4);
|
|
|
+ memcpy(&scsi3addr[0], &log_unit, 4);
|
|
|
+ scsi3addr[3] |= 0x40;
|
|
|
+}
|
|
|
+
|
|
|
+/* This function gets the SCSI vendor, model, and revision of a logical drive
|
|
|
+ * 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,
|
|
|
+ char *vendor, char *model, char *rev)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ InquiryData_struct *inq_buf;
|
|
|
+ unsigned char scsi3addr[8];
|
|
|
+
|
|
|
+ *vendor = '\0';
|
|
|
+ *model = '\0';
|
|
|
+ *rev = '\0';
|
|
|
+
|
|
|
+ inq_buf = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL);
|
|
|
+ if (!inq_buf)
|
|
|
+ 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);
|
|
|
+ if (rc == IO_OK) {
|
|
|
+ memcpy(vendor, &inq_buf->data_byte[8], VENDOR_LEN);
|
|
|
+ vendor[VENDOR_LEN] = '\0';
|
|
|
+ memcpy(model, &inq_buf->data_byte[16], MODEL_LEN);
|
|
|
+ model[MODEL_LEN] = '\0';
|
|
|
+ memcpy(rev, &inq_buf->data_byte[32], REV_LEN);
|
|
|
+ rev[REV_LEN] = '\0';
|
|
|
+ }
|
|
|
+
|
|
|
+ kfree(inq_buf);
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
/* This function gets the serial number of a logical drive via
|
|
|
* inquiry page 0x83. Serial no. is 16 bytes. If the serial
|
|
|
* number cannot be had, for whatever reason, 16 bytes of 0xff
|
|
@@ -1348,6 +1583,7 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq,
|
|
|
#define PAGE_83_INQ_BYTES 64
|
|
|
int rc;
|
|
|
unsigned char *buf;
|
|
|
+ unsigned char scsi3addr[8];
|
|
|
|
|
|
if (buflen > 16)
|
|
|
buflen = 16;
|
|
@@ -1356,12 +1592,13 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq,
|
|
|
if (!buf)
|
|
|
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, 1, logvol, 0x83, TYPE_CMD);
|
|
|
+ PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD);
|
|
|
else
|
|
|
rc = sendcmd(CISS_INQUIRY, ctlr, buf,
|
|
|
- PAGE_83_INQ_BYTES, 1, logvol, 0x83, NULL, TYPE_CMD);
|
|
|
+ PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD);
|
|
|
if (rc == IO_OK)
|
|
|
memcpy(serial_no, &buf[8], buflen);
|
|
|
kfree(buf);
|
|
@@ -1377,7 +1614,7 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
|
|
|
disk->first_minor = drv_index << NWD_SHIFT;
|
|
|
disk->fops = &cciss_fops;
|
|
|
disk->private_data = &h->drv[drv_index];
|
|
|
- disk->driverfs_dev = &h->pdev->dev;
|
|
|
+ disk->driverfs_dev = &h->drv[drv_index].dev;
|
|
|
|
|
|
/* Set up queue information */
|
|
|
blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask);
|
|
@@ -1394,8 +1631,8 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
|
|
|
|
|
|
disk->queue->queuedata = h;
|
|
|
|
|
|
- blk_queue_hardsect_size(disk->queue,
|
|
|
- h->drv[drv_index].block_size);
|
|
|
+ blk_queue_logical_block_size(disk->queue,
|
|
|
+ h->drv[drv_index].block_size);
|
|
|
|
|
|
/* Make sure all queue data is written out before */
|
|
|
/* setting h->drv[drv_index].queue, as setting this */
|
|
@@ -1468,6 +1705,8 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
|
|
|
drvinfo->block_size = block_size;
|
|
|
drvinfo->nr_blocks = total_size + 1;
|
|
|
|
|
|
+ cciss_get_device_descr(ctlr, drv_index, 1, drvinfo->vendor,
|
|
|
+ drvinfo->model, drvinfo->rev);
|
|
|
cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no,
|
|
|
sizeof(drvinfo->serial_no));
|
|
|
|
|
@@ -1517,6 +1756,9 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
|
|
|
h->drv[drv_index].cylinders = drvinfo->cylinders;
|
|
|
h->drv[drv_index].raid_level = drvinfo->raid_level;
|
|
|
memcpy(h->drv[drv_index].serial_no, drvinfo->serial_no, 16);
|
|
|
+ memcpy(h->drv[drv_index].vendor, drvinfo->vendor, VENDOR_LEN + 1);
|
|
|
+ memcpy(h->drv[drv_index].model, drvinfo->model, MODEL_LEN + 1);
|
|
|
+ memcpy(h->drv[drv_index].rev, drvinfo->rev, REV_LEN + 1);
|
|
|
|
|
|
++h->num_luns;
|
|
|
disk = h->gendisk[drv_index];
|
|
@@ -1591,6 +1833,8 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node)
|
|
|
}
|
|
|
}
|
|
|
h->drv[drv_index].LunID = lunid;
|
|
|
+ if (cciss_create_ld_sysfs_entry(h, &h->drv[drv_index], drv_index))
|
|
|
+ goto err_free_disk;
|
|
|
|
|
|
/* Don't need to mark this busy because nobody */
|
|
|
/* else knows about this disk yet to contend */
|
|
@@ -1598,6 +1842,11 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node)
|
|
|
h->drv[drv_index].busy_configuring = 0;
|
|
|
wmb();
|
|
|
return drv_index;
|
|
|
+
|
|
|
+err_free_disk:
|
|
|
+ put_disk(h->gendisk[drv_index]);
|
|
|
+ h->gendisk[drv_index] = NULL;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
/* This is for the special case of a controller which
|
|
@@ -1668,8 +1917,8 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
|
|
|
goto mem_msg;
|
|
|
|
|
|
return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
|
|
|
- sizeof(ReportLunData_struct), 0,
|
|
|
- 0, 0, TYPE_CMD);
|
|
|
+ sizeof(ReportLunData_struct),
|
|
|
+ 0, CTLR_LUNID, TYPE_CMD);
|
|
|
|
|
|
if (return_code == IO_OK)
|
|
|
listlength = be32_to_cpu(*(__be32 *) ld_buff->LUNListLength);
|
|
@@ -1718,6 +1967,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
|
|
|
h->drv[i].busy_configuring = 1;
|
|
|
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
|
|
|
return_code = deregister_disk(h, i, 1);
|
|
|
+ cciss_destroy_ld_sysfs_entry(&h->drv[i]);
|
|
|
h->drv[i].busy_configuring = 0;
|
|
|
}
|
|
|
}
|
|
@@ -1877,11 +2127,9 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller,
|
|
|
- 1: address logical volume log_unit,
|
|
|
- 2: periph device address is scsi3addr */
|
|
|
- unsigned int log_unit, __u8 page_code,
|
|
|
- unsigned char *scsi3addr, int cmd_type)
|
|
|
+static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
|
|
|
+ size_t size, __u8 page_code, unsigned char *scsi3addr,
|
|
|
+ int cmd_type)
|
|
|
{
|
|
|
ctlr_info_t *h = hba[ctlr];
|
|
|
u64bit buff_dma_handle;
|
|
@@ -1897,27 +2145,12 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
|
|
|
c->Header.SGTotal = 0;
|
|
|
}
|
|
|
c->Header.Tag.lower = c->busaddr;
|
|
|
+ memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8);
|
|
|
|
|
|
c->Request.Type.Type = cmd_type;
|
|
|
if (cmd_type == TYPE_CMD) {
|
|
|
switch (cmd) {
|
|
|
case CISS_INQUIRY:
|
|
|
- /* If the logical unit number is 0 then, this is going
|
|
|
- to controller so It's a physical command
|
|
|
- mode = 0 target = 0. So we have nothing to write.
|
|
|
- otherwise, if use_unit_num == 1,
|
|
|
- mode = 1(volume set addressing) target = LUNID
|
|
|
- otherwise, if use_unit_num == 2,
|
|
|
- mode = 0(periph dev addr) target = scsi3addr */
|
|
|
- if (use_unit_num == 1) {
|
|
|
- c->Header.LUN.LogDev.VolId =
|
|
|
- h->drv[log_unit].LunID;
|
|
|
- c->Header.LUN.LogDev.Mode = 1;
|
|
|
- } else if (use_unit_num == 2) {
|
|
|
- memcpy(c->Header.LUN.LunAddrBytes, scsi3addr,
|
|
|
- 8);
|
|
|
- c->Header.LUN.LogDev.Mode = 0;
|
|
|
- }
|
|
|
/* are we trying to read a vital product page */
|
|
|
if (page_code != 0) {
|
|
|
c->Request.CDB[1] = 0x01;
|
|
@@ -1947,8 +2180,6 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
|
|
|
break;
|
|
|
|
|
|
case CCISS_READ_CAPACITY:
|
|
|
- c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID;
|
|
|
- c->Header.LUN.LogDev.Mode = 1;
|
|
|
c->Request.CDBLen = 10;
|
|
|
c->Request.Type.Attribute = ATTR_SIMPLE;
|
|
|
c->Request.Type.Direction = XFER_READ;
|
|
@@ -1956,8 +2187,6 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
|
|
|
c->Request.CDB[0] = cmd;
|
|
|
break;
|
|
|
case CCISS_READ_CAPACITY_16:
|
|
|
- c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID;
|
|
|
- c->Header.LUN.LogDev.Mode = 1;
|
|
|
c->Request.CDBLen = 16;
|
|
|
c->Request.Type.Attribute = ATTR_SIMPLE;
|
|
|
c->Request.Type.Direction = XFER_READ;
|
|
@@ -1979,6 +2208,12 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
|
|
|
c->Request.CDB[0] = BMIC_WRITE;
|
|
|
c->Request.CDB[6] = BMIC_CACHE_FLUSH;
|
|
|
break;
|
|
|
+ case TEST_UNIT_READY:
|
|
|
+ c->Request.CDBLen = 6;
|
|
|
+ c->Request.Type.Attribute = ATTR_SIMPLE;
|
|
|
+ c->Request.Type.Direction = XFER_NONE;
|
|
|
+ c->Request.Timeout = 0;
|
|
|
+ break;
|
|
|
default:
|
|
|
printk(KERN_WARNING
|
|
|
"cciss%d: Unknown Command 0x%c\n", ctlr, cmd);
|
|
@@ -1997,13 +2232,13 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
|
|
|
memcpy(&c->Request.CDB[4], buff, 8);
|
|
|
break;
|
|
|
case 1: /* RESET message */
|
|
|
- c->Request.CDBLen = 12;
|
|
|
+ c->Request.CDBLen = 16;
|
|
|
c->Request.Type.Attribute = ATTR_SIMPLE;
|
|
|
- c->Request.Type.Direction = XFER_WRITE;
|
|
|
+ c->Request.Type.Direction = XFER_NONE;
|
|
|
c->Request.Timeout = 0;
|
|
|
memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
|
|
|
c->Request.CDB[0] = cmd; /* reset */
|
|
|
- c->Request.CDB[1] = 0x04; /* reset a LUN */
|
|
|
+ c->Request.CDB[1] = 0x03; /* reset a target */
|
|
|
break;
|
|
|
case 3: /* No-Op message */
|
|
|
c->Request.CDBLen = 1;
|
|
@@ -2035,114 +2270,152 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
-static int sendcmd_withirq(__u8 cmd,
|
|
|
- int ctlr,
|
|
|
- void *buff,
|
|
|
- size_t size,
|
|
|
- unsigned int use_unit_num,
|
|
|
- unsigned int log_unit, __u8 page_code, int cmd_type)
|
|
|
+static int check_target_status(ctlr_info_t *h, CommandList_struct *c)
|
|
|
{
|
|
|
- ctlr_info_t *h = hba[ctlr];
|
|
|
- CommandList_struct *c;
|
|
|
+ switch (c->err_info->ScsiStatus) {
|
|
|
+ case SAM_STAT_GOOD:
|
|
|
+ return IO_OK;
|
|
|
+ case SAM_STAT_CHECK_CONDITION:
|
|
|
+ switch (0xf & c->err_info->SenseInfo[2]) {
|
|
|
+ case 0: return IO_OK; /* no sense */
|
|
|
+ case 1: return IO_OK; /* recovered error */
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING "cciss%d: cmd 0x%02x "
|
|
|
+ "check condition, sense key = 0x%02x\n",
|
|
|
+ h->ctlr, c->Request.CDB[0],
|
|
|
+ c->err_info->SenseInfo[2]);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING "cciss%d: cmd 0x%02x"
|
|
|
+ "scsi status = 0x%02x\n", h->ctlr,
|
|
|
+ c->Request.CDB[0], c->err_info->ScsiStatus);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return IO_ERROR;
|
|
|
+}
|
|
|
+
|
|
|
+static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c)
|
|
|
+{
|
|
|
+ int return_status = IO_OK;
|
|
|
+
|
|
|
+ if (c->err_info->CommandStatus == CMD_SUCCESS)
|
|
|
+ return IO_OK;
|
|
|
+
|
|
|
+ switch (c->err_info->CommandStatus) {
|
|
|
+ case CMD_TARGET_STATUS:
|
|
|
+ return_status = check_target_status(h, c);
|
|
|
+ break;
|
|
|
+ case CMD_DATA_UNDERRUN:
|
|
|
+ case CMD_DATA_OVERRUN:
|
|
|
+ /* expected for inquiry and report lun commands */
|
|
|
+ break;
|
|
|
+ case CMD_INVALID:
|
|
|
+ printk(KERN_WARNING "cciss: cmd 0x%02x is "
|
|
|
+ "reported invalid\n", c->Request.CDB[0]);
|
|
|
+ return_status = IO_ERROR;
|
|
|
+ break;
|
|
|
+ case CMD_PROTOCOL_ERR:
|
|
|
+ printk(KERN_WARNING "cciss: cmd 0x%02x has "
|
|
|
+ "protocol error \n", c->Request.CDB[0]);
|
|
|
+ return_status = IO_ERROR;
|
|
|
+ break;
|
|
|
+ case CMD_HARDWARE_ERR:
|
|
|
+ printk(KERN_WARNING "cciss: cmd 0x%02x had "
|
|
|
+ " hardware error\n", c->Request.CDB[0]);
|
|
|
+ return_status = IO_ERROR;
|
|
|
+ break;
|
|
|
+ case CMD_CONNECTION_LOST:
|
|
|
+ printk(KERN_WARNING "cciss: cmd 0x%02x had "
|
|
|
+ "connection lost\n", c->Request.CDB[0]);
|
|
|
+ return_status = IO_ERROR;
|
|
|
+ break;
|
|
|
+ case CMD_ABORTED:
|
|
|
+ printk(KERN_WARNING "cciss: cmd 0x%02x was "
|
|
|
+ "aborted\n", c->Request.CDB[0]);
|
|
|
+ return_status = IO_ERROR;
|
|
|
+ break;
|
|
|
+ case CMD_ABORT_FAILED:
|
|
|
+ printk(KERN_WARNING "cciss: cmd 0x%02x reports "
|
|
|
+ "abort failed\n", c->Request.CDB[0]);
|
|
|
+ return_status = IO_ERROR;
|
|
|
+ break;
|
|
|
+ case CMD_UNSOLICITED_ABORT:
|
|
|
+ printk(KERN_WARNING
|
|
|
+ "cciss%d: unsolicited abort 0x%02x\n", h->ctlr,
|
|
|
+ c->Request.CDB[0]);
|
|
|
+ return_status = IO_NEEDS_RETRY;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING "cciss: cmd 0x%02x returned "
|
|
|
+ "unknown status %x\n", c->Request.CDB[0],
|
|
|
+ c->err_info->CommandStatus);
|
|
|
+ return_status = IO_ERROR;
|
|
|
+ }
|
|
|
+ return return_status;
|
|
|
+}
|
|
|
+
|
|
|
+static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
|
|
|
+ int attempt_retry)
|
|
|
+{
|
|
|
+ DECLARE_COMPLETION_ONSTACK(wait);
|
|
|
u64bit buff_dma_handle;
|
|
|
unsigned long flags;
|
|
|
- int return_status;
|
|
|
- DECLARE_COMPLETION_ONSTACK(wait);
|
|
|
+ int return_status = IO_OK;
|
|
|
|
|
|
- if ((c = cmd_alloc(h, 0)) == NULL)
|
|
|
- return -ENOMEM;
|
|
|
- return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
|
|
|
- log_unit, page_code, NULL, cmd_type);
|
|
|
- if (return_status != IO_OK) {
|
|
|
- cmd_free(h, c, 0);
|
|
|
- return return_status;
|
|
|
- }
|
|
|
- resend_cmd2:
|
|
|
+resend_cmd2:
|
|
|
c->waiting = &wait;
|
|
|
-
|
|
|
/* Put the request on the tail of the queue and send it */
|
|
|
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
|
|
|
+ spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
|
|
|
addQ(&h->reqQ, c);
|
|
|
h->Qdepth++;
|
|
|
start_io(h);
|
|
|
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
|
|
|
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
|
|
|
|
|
|
wait_for_completion(&wait);
|
|
|
|
|
|
- if (c->err_info->CommandStatus != 0) { /* an error has occurred */
|
|
|
- switch (c->err_info->CommandStatus) {
|
|
|
- case CMD_TARGET_STATUS:
|
|
|
- printk(KERN_WARNING "cciss: cmd %p has "
|
|
|
- " completed with errors\n", c);
|
|
|
- if (c->err_info->ScsiStatus) {
|
|
|
- printk(KERN_WARNING "cciss: cmd %p "
|
|
|
- "has SCSI Status = %x\n",
|
|
|
- c, c->err_info->ScsiStatus);
|
|
|
- }
|
|
|
+ if (c->err_info->CommandStatus == 0 || !attempt_retry)
|
|
|
+ goto command_done;
|
|
|
|
|
|
- break;
|
|
|
- case CMD_DATA_UNDERRUN:
|
|
|
- case CMD_DATA_OVERRUN:
|
|
|
- /* expected for inquire and report lun commands */
|
|
|
- break;
|
|
|
- case CMD_INVALID:
|
|
|
- printk(KERN_WARNING "cciss: Cmd %p is "
|
|
|
- "reported invalid\n", c);
|
|
|
- return_status = IO_ERROR;
|
|
|
- break;
|
|
|
- case CMD_PROTOCOL_ERR:
|
|
|
- printk(KERN_WARNING "cciss: cmd %p has "
|
|
|
- "protocol error \n", c);
|
|
|
- return_status = IO_ERROR;
|
|
|
- break;
|
|
|
- case CMD_HARDWARE_ERR:
|
|
|
- printk(KERN_WARNING "cciss: cmd %p had "
|
|
|
- " hardware error\n", c);
|
|
|
- return_status = IO_ERROR;
|
|
|
- break;
|
|
|
- case CMD_CONNECTION_LOST:
|
|
|
- printk(KERN_WARNING "cciss: cmd %p had "
|
|
|
- "connection lost\n", c);
|
|
|
- return_status = IO_ERROR;
|
|
|
- break;
|
|
|
- case CMD_ABORTED:
|
|
|
- printk(KERN_WARNING "cciss: cmd %p was "
|
|
|
- "aborted\n", c);
|
|
|
- return_status = IO_ERROR;
|
|
|
- break;
|
|
|
- case CMD_ABORT_FAILED:
|
|
|
- printk(KERN_WARNING "cciss: cmd %p reports "
|
|
|
- "abort failed\n", c);
|
|
|
- return_status = IO_ERROR;
|
|
|
- break;
|
|
|
- case CMD_UNSOLICITED_ABORT:
|
|
|
- printk(KERN_WARNING
|
|
|
- "cciss%d: unsolicited abort %p\n", ctlr, c);
|
|
|
- if (c->retry_count < MAX_CMD_RETRIES) {
|
|
|
- printk(KERN_WARNING
|
|
|
- "cciss%d: retrying %p\n", ctlr, c);
|
|
|
- c->retry_count++;
|
|
|
- /* erase the old error information */
|
|
|
- memset(c->err_info, 0,
|
|
|
- sizeof(ErrorInfo_struct));
|
|
|
- return_status = IO_OK;
|
|
|
- INIT_COMPLETION(wait);
|
|
|
- goto resend_cmd2;
|
|
|
- }
|
|
|
- return_status = IO_ERROR;
|
|
|
- break;
|
|
|
- default:
|
|
|
- printk(KERN_WARNING "cciss: cmd %p returned "
|
|
|
- "unknown status %x\n", c,
|
|
|
- c->err_info->CommandStatus);
|
|
|
- return_status = IO_ERROR;
|
|
|
- }
|
|
|
+ return_status = process_sendcmd_error(h, c);
|
|
|
+
|
|
|
+ if (return_status == IO_NEEDS_RETRY &&
|
|
|
+ c->retry_count < MAX_CMD_RETRIES) {
|
|
|
+ printk(KERN_WARNING "cciss%d: retrying 0x%02x\n", h->ctlr,
|
|
|
+ c->Request.CDB[0]);
|
|
|
+ c->retry_count++;
|
|
|
+ /* erase the old error information */
|
|
|
+ memset(c->err_info, 0, sizeof(ErrorInfo_struct));
|
|
|
+ return_status = IO_OK;
|
|
|
+ INIT_COMPLETION(wait);
|
|
|
+ goto resend_cmd2;
|
|
|
}
|
|
|
+
|
|
|
+command_done:
|
|
|
/* unlock the buffers 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 return_status;
|
|
|
+}
|
|
|
+
|
|
|
+static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
|
|
|
+ __u8 page_code, unsigned char scsi3addr[],
|
|
|
+ int cmd_type)
|
|
|
+{
|
|
|
+ ctlr_info_t *h = hba[ctlr];
|
|
|
+ CommandList_struct *c;
|
|
|
+ int return_status;
|
|
|
+
|
|
|
+ c = cmd_alloc(h, 0);
|
|
|
+ if (!c)
|
|
|
+ return -ENOMEM;
|
|
|
+ return_status = fill_cmd(c, cmd, ctlr, buff, size, page_code,
|
|
|
+ scsi3addr, cmd_type);
|
|
|
+ if (return_status == IO_OK)
|
|
|
+ return_status = sendcmd_withirq_core(h, c, 1);
|
|
|
+
|
|
|
cmd_free(h, c, 0);
|
|
|
return return_status;
|
|
|
}
|
|
@@ -2155,15 +2428,17 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
|
|
|
{
|
|
|
int return_code;
|
|
|
unsigned long t;
|
|
|
+ unsigned char scsi3addr[8];
|
|
|
|
|
|
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), 1,
|
|
|
- logvol, 0xC1, TYPE_CMD);
|
|
|
+ inq_buff, sizeof(*inq_buff),
|
|
|
+ 0xC1, scsi3addr, TYPE_CMD);
|
|
|
else
|
|
|
return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff,
|
|
|
- sizeof(*inq_buff), 1, logvol, 0xC1, NULL,
|
|
|
+ sizeof(*inq_buff), 0xC1, scsi3addr,
|
|
|
TYPE_CMD);
|
|
|
if (return_code == IO_OK) {
|
|
|
if (inq_buff->data_byte[8] == 0xFF) {
|
|
@@ -2204,6 +2479,7 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
|
|
|
{
|
|
|
ReadCapdata_struct *buf;
|
|
|
int return_code;
|
|
|
+ unsigned char scsi3addr[8];
|
|
|
|
|
|
buf = kzalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
|
|
|
if (!buf) {
|
|
@@ -2211,14 +2487,15 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
|
|
|
if (withirq)
|
|
|
return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
|
|
|
ctlr, buf, sizeof(ReadCapdata_struct),
|
|
|
- 1, logvol, 0, TYPE_CMD);
|
|
|
+ 0, scsi3addr, TYPE_CMD);
|
|
|
else
|
|
|
return_code = sendcmd(CCISS_READ_CAPACITY,
|
|
|
ctlr, buf, sizeof(ReadCapdata_struct),
|
|
|
- 1, logvol, 0, NULL, TYPE_CMD);
|
|
|
+ 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);
|
|
@@ -2238,6 +2515,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,
|
|
|
{
|
|
|
ReadCapdata_struct_16 *buf;
|
|
|
int return_code;
|
|
|
+ unsigned char scsi3addr[8];
|
|
|
|
|
|
buf = kzalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
|
|
|
if (!buf) {
|
|
@@ -2245,15 +2523,16 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
|
|
|
if (withirq) {
|
|
|
return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16,
|
|
|
ctlr, buf, sizeof(ReadCapdata_struct_16),
|
|
|
- 1, logvol, 0, TYPE_CMD);
|
|
|
+ 0, scsi3addr, TYPE_CMD);
|
|
|
}
|
|
|
else {
|
|
|
return_code = sendcmd(CCISS_READ_CAPACITY_16,
|
|
|
ctlr, buf, sizeof(ReadCapdata_struct_16),
|
|
|
- 1, logvol, 0, NULL, TYPE_CMD);
|
|
|
+ 0, scsi3addr, TYPE_CMD);
|
|
|
}
|
|
|
if (return_code == IO_OK) {
|
|
|
*total_size = be64_to_cpu(*(__be64 *) buf->total_size);
|
|
@@ -2303,7 +2582,7 @@ static int cciss_revalidate(struct gendisk *disk)
|
|
|
cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size,
|
|
|
inq_buff, drv);
|
|
|
|
|
|
- blk_queue_hardsect_size(drv->queue, drv->block_size);
|
|
|
+ blk_queue_logical_block_size(drv->queue, drv->block_size);
|
|
|
set_capacity(disk, drv->nr_blocks);
|
|
|
|
|
|
kfree(inq_buff);
|
|
@@ -2333,86 +2612,21 @@ static unsigned long pollcomplete(int ctlr)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
|
|
|
-{
|
|
|
- /* We get in here if sendcmd() is polling for completions
|
|
|
- and gets some command back that it wasn't expecting --
|
|
|
- something other than that which it just sent down.
|
|
|
- Ordinarily, that shouldn't happen, but it can happen when
|
|
|
- the scsi tape stuff gets into error handling mode, and
|
|
|
- starts using sendcmd() to try to abort commands and
|
|
|
- reset tape drives. In that case, sendcmd may pick up
|
|
|
- completions of commands that were sent to logical drives
|
|
|
- through the block i/o system, or cciss ioctls completing, etc.
|
|
|
- In that case, we need to save those completions for later
|
|
|
- processing by the interrupt handler.
|
|
|
- */
|
|
|
-
|
|
|
-#ifdef CONFIG_CISS_SCSI_TAPE
|
|
|
- struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects;
|
|
|
-
|
|
|
- /* If it's not the scsi tape stuff doing error handling, (abort */
|
|
|
- /* or reset) then we don't expect anything weird. */
|
|
|
- if (cmd != CCISS_RESET_MSG && cmd != CCISS_ABORT_MSG) {
|
|
|
-#endif
|
|
|
- printk(KERN_WARNING "cciss cciss%d: SendCmd "
|
|
|
- "Invalid command list address returned! (%lx)\n",
|
|
|
- ctlr, complete);
|
|
|
- /* not much we can do. */
|
|
|
-#ifdef CONFIG_CISS_SCSI_TAPE
|
|
|
- return 1;
|
|
|
- }
|
|
|
-
|
|
|
- /* We've sent down an abort or reset, but something else
|
|
|
- has completed */
|
|
|
- if (srl->ncompletions >= (hba[ctlr]->nr_cmds + 2)) {
|
|
|
- /* Uh oh. No room to save it for later... */
|
|
|
- printk(KERN_WARNING "cciss%d: Sendcmd: Invalid command addr, "
|
|
|
- "reject list overflow, command lost!\n", ctlr);
|
|
|
- return 1;
|
|
|
- }
|
|
|
- /* Save it for later */
|
|
|
- srl->complete[srl->ncompletions] = complete;
|
|
|
- srl->ncompletions++;
|
|
|
-#endif
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Send a command to the controller, and wait for it to complete.
|
|
|
- * Only used at init time.
|
|
|
+/* 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(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller,
|
|
|
- 1: address logical volume log_unit,
|
|
|
- 2: periph device address is scsi3addr */
|
|
|
- unsigned int log_unit,
|
|
|
- __u8 page_code, unsigned char *scsi3addr, int cmd_type)
|
|
|
+static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c)
|
|
|
{
|
|
|
- CommandList_struct *c;
|
|
|
int i;
|
|
|
unsigned long complete;
|
|
|
- ctlr_info_t *info_p = hba[ctlr];
|
|
|
+ int status = IO_ERROR;
|
|
|
u64bit buff_dma_handle;
|
|
|
- int status, done = 0;
|
|
|
|
|
|
- if ((c = cmd_alloc(info_p, 1)) == NULL) {
|
|
|
- printk(KERN_WARNING "cciss: unable to get memory");
|
|
|
- return IO_ERROR;
|
|
|
- }
|
|
|
- status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
|
|
|
- log_unit, page_code, scsi3addr, cmd_type);
|
|
|
- if (status != IO_OK) {
|
|
|
- cmd_free(info_p, c, 1);
|
|
|
- return status;
|
|
|
- }
|
|
|
- resend_cmd1:
|
|
|
- /*
|
|
|
- * Disable interrupt
|
|
|
- */
|
|
|
-#ifdef CCISS_DEBUG
|
|
|
- printk(KERN_DEBUG "cciss: turning intr off\n");
|
|
|
-#endif /* CCISS_DEBUG */
|
|
|
- info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
|
|
|
+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 */
|
|
@@ -2420,21 +2634,15 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use
|
|
|
/* tape side of the driver. */
|
|
|
for (i = 200000; i > 0; i--) {
|
|
|
/* if fifo isn't full go */
|
|
|
- if (!(info_p->access.fifo_full(info_p))) {
|
|
|
-
|
|
|
+ if (!(h->access.fifo_full(h)))
|
|
|
break;
|
|
|
- }
|
|
|
udelay(10);
|
|
|
printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
|
|
|
- " waiting!\n", ctlr);
|
|
|
+ " waiting!\n", h->ctlr);
|
|
|
}
|
|
|
- /*
|
|
|
- * Send the cmd
|
|
|
- */
|
|
|
- info_p->access.submit_command(info_p, c);
|
|
|
- done = 0;
|
|
|
+ h->access.submit_command(h, c); /* Send the cmd */
|
|
|
do {
|
|
|
- complete = pollcomplete(ctlr);
|
|
|
+ complete = pollcomplete(h->ctlr);
|
|
|
|
|
|
#ifdef CCISS_DEBUG
|
|
|
printk(KERN_DEBUG "cciss: command completed\n");
|
|
@@ -2443,97 +2651,102 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use
|
|
|
if (complete == 1) {
|
|
|
printk(KERN_WARNING
|
|
|
"cciss cciss%d: SendCmd Timeout out, "
|
|
|
- "No command list address returned!\n", ctlr);
|
|
|
+ "No command list address returned!\n", h->ctlr);
|
|
|
status = IO_ERROR;
|
|
|
- done = 1;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- /* This will need to change for direct lookup completions */
|
|
|
- if ((complete & CISS_ERROR_BIT)
|
|
|
- && (complete & ~CISS_ERROR_BIT) == c->busaddr) {
|
|
|
- /* 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;
|
|
|
- } else {
|
|
|
- if (c->err_info->CommandStatus ==
|
|
|
- CMD_UNSOLICITED_ABORT) {
|
|
|
- printk(KERN_WARNING "cciss%d: "
|
|
|
- "unsolicited abort %p\n",
|
|
|
- ctlr, c);
|
|
|
- if (c->retry_count < MAX_CMD_RETRIES) {
|
|
|
- printk(KERN_WARNING
|
|
|
- "cciss%d: retrying %p\n",
|
|
|
- ctlr, c);
|
|
|
- c->retry_count++;
|
|
|
- /* erase the old error */
|
|
|
- /* information */
|
|
|
- memset(c->err_info, 0,
|
|
|
- sizeof
|
|
|
- (ErrorInfo_struct));
|
|
|
- goto resend_cmd1;
|
|
|
- } else {
|
|
|
- printk(KERN_WARNING
|
|
|
- "cciss%d: retried %p too "
|
|
|
- "many times\n", ctlr, c);
|
|
|
- status = IO_ERROR;
|
|
|
- goto cleanup1;
|
|
|
- }
|
|
|
- } else if (c->err_info->CommandStatus ==
|
|
|
- CMD_UNABORTABLE) {
|
|
|
- printk(KERN_WARNING
|
|
|
- "cciss%d: command could not be aborted.\n",
|
|
|
- ctlr);
|
|
|
- status = IO_ERROR;
|
|
|
- goto cleanup1;
|
|
|
- }
|
|
|
- printk(KERN_WARNING "ciss ciss%d: sendcmd"
|
|
|
- " Error %x \n", ctlr,
|
|
|
- c->err_info->CommandStatus);
|
|
|
- printk(KERN_WARNING "ciss ciss%d: sendcmd"
|
|
|
- " offensive info\n"
|
|
|
- " size %x\n num %x value %x\n",
|
|
|
- ctlr,
|
|
|
- c->err_info->MoreErrInfo.Invalid_Cmd.
|
|
|
- offense_size,
|
|
|
- c->err_info->MoreErrInfo.Invalid_Cmd.
|
|
|
- offense_num,
|
|
|
- c->err_info->MoreErrInfo.Invalid_Cmd.
|
|
|
- offense_value);
|
|
|
- status = IO_ERROR;
|
|
|
- goto cleanup1;
|
|
|
- }
|
|
|
+ /* 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;
|
|
|
}
|
|
|
- /* This will need changing for direct lookup completions */
|
|
|
- if (complete != c->busaddr) {
|
|
|
- if (add_sendcmd_reject(cmd, ctlr, complete) != 0) {
|
|
|
- BUG(); /* we are pretty much hosed if we get here. */
|
|
|
+
|
|
|
+ /* 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;
|
|
|
}
|
|
|
- continue;
|
|
|
- } else
|
|
|
- done = 1;
|
|
|
- } while (!done);
|
|
|
+ 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);
|
|
|
|
|
|
- cleanup1:
|
|
|
/* 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(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
|
|
|
+ pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val,
|
|
|
c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
|
|
|
-#ifdef CONFIG_CISS_SCSI_TAPE
|
|
|
- /* if we saved some commands for later, process them now. */
|
|
|
- if (info_p->scsi_rejects.ncompletions > 0)
|
|
|
- do_cciss_intr(0, info_p);
|
|
|
-#endif
|
|
|
- cmd_free(info_p, c, 1);
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
@@ -2691,7 +2904,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
|
|
|
printk(KERN_WARNING "cciss: cmd %p has"
|
|
|
" completed with data underrun "
|
|
|
"reported\n", cmd);
|
|
|
- cmd->rq->data_len = cmd->err_info->ResidualCnt;
|
|
|
+ cmd->rq->resid_len = cmd->err_info->ResidualCnt;
|
|
|
}
|
|
|
break;
|
|
|
case CMD_DATA_OVERRUN:
|
|
@@ -2806,7 +3019,7 @@ static void do_cciss_request(struct request_queue *q)
|
|
|
goto startio;
|
|
|
|
|
|
queue:
|
|
|
- creq = elv_next_request(q);
|
|
|
+ creq = blk_peek_request(q);
|
|
|
if (!creq)
|
|
|
goto startio;
|
|
|
|
|
@@ -2815,7 +3028,7 @@ static void do_cciss_request(struct request_queue *q)
|
|
|
if ((c = cmd_alloc(h, 1)) == NULL)
|
|
|
goto full;
|
|
|
|
|
|
- blkdev_dequeue_request(creq);
|
|
|
+ blk_start_request(creq);
|
|
|
|
|
|
spin_unlock_irq(q->queue_lock);
|
|
|
|
|
@@ -2840,10 +3053,10 @@ static void do_cciss_request(struct request_queue *q)
|
|
|
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 = creq->sector;
|
|
|
+ start_blk = blk_rq_pos(creq);
|
|
|
#ifdef CCISS_DEBUG
|
|
|
- printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", (int)creq->sector,
|
|
|
- (int)creq->nr_sectors);
|
|
|
+ printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",
|
|
|
+ (int)blk_rq_pos(creq), (int)blk_rq_sectors(creq));
|
|
|
#endif /* CCISS_DEBUG */
|
|
|
|
|
|
sg_init_table(tmp_sg, MAXSGENTRIES);
|
|
@@ -2869,8 +3082,8 @@ static void do_cciss_request(struct request_queue *q)
|
|
|
h->maxSG = seg;
|
|
|
|
|
|
#ifdef CCISS_DEBUG
|
|
|
- printk(KERN_DEBUG "cciss: Submitting %lu sectors in %d segments\n",
|
|
|
- creq->nr_sectors, seg);
|
|
|
+ printk(KERN_DEBUG "cciss: Submitting %u sectors in %d segments\n",
|
|
|
+ blk_rq_sectors(creq), seg);
|
|
|
#endif /* CCISS_DEBUG */
|
|
|
|
|
|
c->Header.SGList = c->Header.SGTotal = seg;
|
|
@@ -2882,8 +3095,8 @@ static void do_cciss_request(struct request_queue *q)
|
|
|
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[7] = (creq->nr_sectors >> 8) & 0xff;
|
|
|
- c->Request.CDB[8] = creq->nr_sectors & 0xff;
|
|
|
+ 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;
|
|
|
} else {
|
|
|
u32 upper32 = upper_32_bits(start_blk);
|
|
@@ -2898,10 +3111,10 @@ static void do_cciss_request(struct request_queue *q)
|
|
|
c->Request.CDB[7]= (start_blk >> 16) & 0xff;
|
|
|
c->Request.CDB[8]= (start_blk >> 8) & 0xff;
|
|
|
c->Request.CDB[9]= start_blk & 0xff;
|
|
|
- c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff;
|
|
|
- c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff;
|
|
|
- c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff;
|
|
|
- c->Request.CDB[13]= creq->nr_sectors & 0xff;
|
|
|
+ c->Request.CDB[10]= (blk_rq_sectors(creq) >> 24) & 0xff;
|
|
|
+ c->Request.CDB[11]= (blk_rq_sectors(creq) >> 16) & 0xff;
|
|
|
+ c->Request.CDB[12]= (blk_rq_sectors(creq) >> 8) & 0xff;
|
|
|
+ c->Request.CDB[13]= blk_rq_sectors(creq) & 0xff;
|
|
|
c->Request.CDB[14] = c->Request.CDB[15] = 0;
|
|
|
}
|
|
|
} else if (blk_pc_request(creq)) {
|
|
@@ -2931,44 +3144,18 @@ startio:
|
|
|
|
|
|
static inline unsigned long get_next_completion(ctlr_info_t *h)
|
|
|
{
|
|
|
-#ifdef CONFIG_CISS_SCSI_TAPE
|
|
|
- /* Any rejects from sendcmd() lying around? Process them first */
|
|
|
- if (h->scsi_rejects.ncompletions == 0)
|
|
|
- return h->access.command_completed(h);
|
|
|
- else {
|
|
|
- struct sendcmd_reject_list *srl;
|
|
|
- int n;
|
|
|
- srl = &h->scsi_rejects;
|
|
|
- n = --srl->ncompletions;
|
|
|
- /* printk("cciss%d: processing saved reject\n", h->ctlr); */
|
|
|
- printk("p");
|
|
|
- return srl->complete[n];
|
|
|
- }
|
|
|
-#else
|
|
|
return h->access.command_completed(h);
|
|
|
-#endif
|
|
|
}
|
|
|
|
|
|
static inline int interrupt_pending(ctlr_info_t *h)
|
|
|
{
|
|
|
-#ifdef CONFIG_CISS_SCSI_TAPE
|
|
|
- return (h->access.intr_pending(h)
|
|
|
- || (h->scsi_rejects.ncompletions > 0));
|
|
|
-#else
|
|
|
return h->access.intr_pending(h);
|
|
|
-#endif
|
|
|
}
|
|
|
|
|
|
static inline long interrupt_not_for_us(ctlr_info_t *h)
|
|
|
{
|
|
|
-#ifdef CONFIG_CISS_SCSI_TAPE
|
|
|
- return (((h->access.intr_pending(h) == 0) ||
|
|
|
- (h->interrupts_enabled == 0))
|
|
|
- && (h->scsi_rejects.ncompletions == 0));
|
|
|
-#else
|
|
|
return (((h->access.intr_pending(h) == 0) ||
|
|
|
(h->interrupts_enabled == 0)));
|
|
|
-#endif
|
|
|
}
|
|
|
|
|
|
static irqreturn_t do_cciss_intr(int irq, void *dev_id)
|
|
@@ -3723,12 +3910,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
|
|
|
INIT_HLIST_HEAD(&hba[i]->reqQ);
|
|
|
|
|
|
if (cciss_pci_init(hba[i], pdev) != 0)
|
|
|
- goto clean1;
|
|
|
+ goto clean0;
|
|
|
|
|
|
sprintf(hba[i]->devname, "cciss%d", i);
|
|
|
hba[i]->ctlr = i;
|
|
|
hba[i]->pdev = pdev;
|
|
|
|
|
|
+ if (cciss_create_hba_sysfs_entry(hba[i]))
|
|
|
+ goto clean0;
|
|
|
+
|
|
|
/* configure PCI DMA stuff */
|
|
|
if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
|
|
|
dac = 1;
|
|
@@ -3787,15 +3977,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
|
|
|
printk(KERN_ERR "cciss: out of memory");
|
|
|
goto clean4;
|
|
|
}
|
|
|
-#ifdef CONFIG_CISS_SCSI_TAPE
|
|
|
- hba[i]->scsi_rejects.complete =
|
|
|
- kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) *
|
|
|
- (hba[i]->nr_cmds + 5), GFP_KERNEL);
|
|
|
- if (hba[i]->scsi_rejects.complete == NULL) {
|
|
|
- printk(KERN_ERR "cciss: out of memory");
|
|
|
- goto clean4;
|
|
|
- }
|
|
|
-#endif
|
|
|
spin_lock_init(&hba[i]->lock);
|
|
|
|
|
|
/* Initialize the pdev driver private data.
|
|
@@ -3828,7 +4009,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
|
|
|
}
|
|
|
|
|
|
return_code = sendcmd_withirq(CISS_INQUIRY, i, inq_buff,
|
|
|
- sizeof(InquiryData_struct), 0, 0 , 0, TYPE_CMD);
|
|
|
+ sizeof(InquiryData_struct), 0, CTLR_LUNID, TYPE_CMD);
|
|
|
if (return_code == IO_OK) {
|
|
|
hba[i]->firm_ver[0] = inq_buff->data_byte[32];
|
|
|
hba[i]->firm_ver[1] = inq_buff->data_byte[33];
|
|
@@ -3855,9 +4036,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
|
|
|
|
|
|
clean4:
|
|
|
kfree(inq_buff);
|
|
|
-#ifdef CONFIG_CISS_SCSI_TAPE
|
|
|
- kfree(hba[i]->scsi_rejects.complete);
|
|
|
-#endif
|
|
|
kfree(hba[i]->cmd_pool_bits);
|
|
|
if (hba[i]->cmd_pool)
|
|
|
pci_free_consistent(hba[i]->pdev,
|
|
@@ -3872,6 +4050,8 @@ clean4:
|
|
|
clean2:
|
|
|
unregister_blkdev(hba[i]->major, hba[i]->devname);
|
|
|
clean1:
|
|
|
+ cciss_destroy_hba_sysfs_entry(hba[i]);
|
|
|
+clean0:
|
|
|
hba[i]->busy_initializing = 0;
|
|
|
/* cleanup any queues that may have been initialized */
|
|
|
for (j=0; j <= hba[i]->highest_lun; j++){
|
|
@@ -3907,8 +4087,8 @@ static void cciss_shutdown(struct pci_dev *pdev)
|
|
|
/* 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, 0, 0, NULL,
|
|
|
- TYPE_CMD);
|
|
|
+ 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 {
|
|
@@ -3973,15 +4153,13 @@ 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);
|
|
|
-#ifdef CONFIG_CISS_SCSI_TAPE
|
|
|
- kfree(hba[i]->scsi_rejects.complete);
|
|
|
-#endif
|
|
|
/*
|
|
|
* 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);
|
|
|
+ cciss_destroy_hba_sysfs_entry(hba[i]);
|
|
|
free_hba(i);
|
|
|
}
|
|
|
|
|
@@ -3999,6 +4177,8 @@ static struct pci_driver cciss_pci_driver = {
|
|
|
*/
|
|
|
static int __init cciss_init(void)
|
|
|
{
|
|
|
+ int err;
|
|
|
+
|
|
|
/*
|
|
|
* The hardware requires that commands are aligned on a 64-bit
|
|
|
* boundary. Given that we use pci_alloc_consistent() to allocate an
|
|
@@ -4008,8 +4188,20 @@ static int __init cciss_init(void)
|
|
|
|
|
|
printk(KERN_INFO DRIVER_NAME "\n");
|
|
|
|
|
|
+ err = bus_register(&cciss_bus_type);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
/* Register for our PCI devices */
|
|
|
- return pci_register_driver(&cciss_pci_driver);
|
|
|
+ err = pci_register_driver(&cciss_pci_driver);
|
|
|
+ if (err)
|
|
|
+ goto err_bus_register;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err_bus_register:
|
|
|
+ bus_unregister(&cciss_bus_type);
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
static void __exit cciss_cleanup(void)
|
|
@@ -4026,6 +4218,7 @@ static void __exit cciss_cleanup(void)
|
|
|
}
|
|
|
}
|
|
|
remove_proc_entry("driver/cciss", NULL);
|
|
|
+ bus_unregister(&cciss_bus_type);
|
|
|
}
|
|
|
|
|
|
static void fail_all_cmds(unsigned long ctlr)
|