Patch 1 of 3 Sorry to take so long to repost. This patch exports more attributes to /sys so we can work work better with udev. Some distros use unique_id among other attributes. This patch attempts to provide that and other attributes to reveal more information about cciss devices in /sys. It's also an effort to be more sysfs friendly. Please consider this for inclusion. Signed-off-by: Mike Miller diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 7d70496..54080e6 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -229,20 +229,485 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr, return c; } +static inline int find_drv_index(int ctlr, drive_info_struct *drv){ + int i; + for (i=0; i < CISS_MAX_LUN; i++) { + if (hba[ctlr]->drv[i].LunID == drv->LunID) + return i; + } + return i; +} + #include "cciss_scsi.c" /* For SCSI tape support */ +#define ENG_GIG 1000000000 +#define ENG_GIG_FACTOR (ENG_GIG/512) #define RAID_UNKNOWN 6 +static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", + "UNKNOWN"}; + + +static spinlock_t sysfs_lock = SPIN_LOCK_UNLOCKED; + +static void cciss_sysfs_stat_inquiry(int ctlr, int logvol, + int withirq, drive_info_struct *drv) +{ + int return_code; + InquiryData_struct *inq_buff; + + /* If there are no heads then this is the controller disk and + * not a valid logical drive so don't query it. + */ + if (!drv->heads) + return; + + inq_buff = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL); + if (!inq_buff) { + printk(KERN_ERR "cciss: out of memory\n"); + goto err; + } + + if (withirq) + return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, + inq_buff, sizeof(*inq_buff), 1, logvol ,0, TYPE_CMD); + else + return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff, + sizeof(*inq_buff), 1, logvol , 0, NULL, TYPE_CMD); + if (return_code == IO_OK) { + memcpy(drv->vendor, &inq_buff->data_byte[8], 8); + drv->vendor[8]='\0'; + memcpy(drv->model, &inq_buff->data_byte[16], 16); + drv->model[16] = '\0'; + memcpy(drv->rev, &inq_buff->data_byte[32], 4); + drv->rev[4] = '\0'; + } else { /* Get geometry failed */ + printk(KERN_WARNING "cciss: inquiry for VPD page 0 failed\n"); + } + + if (withirq) + return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, + inq_buff, sizeof(*inq_buff), 1, logvol ,0x83, TYPE_CMD); + else + return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff, + sizeof(*inq_buff), 1, logvol , 0x83, NULL, TYPE_CMD); + + if (return_code == IO_OK) { + memcpy(drv->uid, &inq_buff->data_byte[8], 16); + } else { /* Get geometry failed */ + printk(KERN_WARNING "cciss: inquiry for VPD page 83 failed\n"); + } + + kfree(inq_buff); +err: + drv->vendor[8] = '\0'; + drv->model[16] = '\0'; + drv->rev[4] = '\0'; + +} + +static ssize_t cciss_show_raid_level(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drv_dynamic *d; + drive_info_struct *drv; + ctlr_info_t *h; + unsigned long flags; + int raid; + + d = container_of(dev, struct drv_dynamic, dev); + spin_lock(&sysfs_lock); + if (!d->disk) { + spin_unlock(&sysfs_lock); + return -ENOENT; + } + + h = get_host(d->disk); + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return snprintf(buf, 30, "Device busy configuring\n"); + } + + drv = d->disk->private_data; + if ((drv->raid_level < 0) || (drv->raid_level) > 5) + raid = RAID_UNKNOWN; + else + raid = drv->raid_level; + + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return snprintf(buf, 20, "RAID %s\n", raid_label[raid]); +} + +static ssize_t cciss_show_disk_size(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drv_dynamic *d; + drive_info_struct *drv; + ctlr_info_t *h; + unsigned long flags; + sector_t vol_sz, vol_sz_frac; + + d = container_of(dev, struct drv_dynamic, dev); + spin_lock(&sysfs_lock); + if (!d->disk) { + spin_unlock(&sysfs_lock); + return -ENOENT; + } + h = get_host(d->disk); + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return snprintf(buf, 30, "Device busy configuring\n"); + } + + drv = d->disk->private_data; + 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); + + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return snprintf(buf, 30, "%4u.%02uGB\n", (int)vol_sz, (int)vol_sz_frac); +} + +static ssize_t cciss_show_usage_count(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drv_dynamic *d; + drive_info_struct *drv; + int count; + + d = container_of(dev, struct drv_dynamic, dev); + spin_lock(&sysfs_lock); + if (!d->disk) { + spin_unlock(&sysfs_lock); + return -ENOENT; + } + drv = d->disk->private_data; + count = drv->usage_count; + spin_unlock(&sysfs_lock); + return snprintf(buf, 20, "%d\n", count); +} + +static ssize_t cciss_show_vendor(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drv_dynamic *d; + drive_info_struct *drv; + ctlr_info_t *h; + unsigned long flags; + int drv_index; + + d = container_of(dev, struct drv_dynamic, dev); + spin_lock(&sysfs_lock); + if (!d->disk) { + spin_unlock(&sysfs_lock); + return -ENOENT; + } + + h = get_host(d->disk); + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -EBUSY; + } + + drv = d->disk->private_data; + + if (!drv->heads) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -ENOTTY; + } + + drv_index = find_drv_index(h->ctlr, drv); + if (drv_index != CISS_MAX_LUN) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return snprintf(buf, 20, "%s\n", (char *)drv->vendor); + } + + printk(KERN_ERR "cciss: logical drive not found\n"); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -ENOTTY; +} + +static ssize_t cciss_show_model(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drv_dynamic *d; + drive_info_struct *drv; + ctlr_info_t *h; + unsigned long flags; + int drv_index; + + d = container_of(dev, struct drv_dynamic, dev); + spin_lock(&sysfs_lock); + if (!d->disk) { + spin_unlock(&sysfs_lock); + return -ENOENT; + } + + h = get_host(d->disk); + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -EBUSY; + } + + drv = d->disk->private_data; + + if (!drv->heads) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -ENOTTY; + } + + drv_index = find_drv_index(h->ctlr, drv); + if (drv_index != CISS_MAX_LUN) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return snprintf(buf, 20, "%s\n", (char *)drv->model); + } + printk(KERN_ERR "cciss: logical drive not found\n"); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -ENOTTY; +} + +static ssize_t cciss_show_rev(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drv_dynamic *d; + drive_info_struct *drv; + ctlr_info_t *h; + unsigned long flags; + int drv_index; + + d = container_of(dev, struct drv_dynamic, dev); + spin_lock(&sysfs_lock); + if (!d->disk) { + spin_unlock(&sysfs_lock); + return -ENOENT; + } + + h = get_host(d->disk); + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -EBUSY; + } + + drv = d->disk->private_data; + + if (!drv->heads) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -ENOTTY; + } + + drv_index = find_drv_index(h->ctlr, drv); + if (drv_index != CISS_MAX_LUN) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return snprintf(buf, 20, "%s\n", (char *)drv->rev); + } + + printk(KERN_ERR "cciss: logical drive not found\n"); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -ENOTTY; +} + +static ssize_t cciss_show_unique_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drv_dynamic *d; + drive_info_struct *drv; + ctlr_info_t *h; + unsigned long flags; + int drv_index; + + d = container_of(dev, struct drv_dynamic, dev); + spin_lock(&sysfs_lock); + if (!d->disk) { + spin_unlock(&sysfs_lock); + return -ENOENT; + } + + h = get_host(d->disk); + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return snprintf(buf, 30, "Device busy configuring\n"); + } + drv = d->disk->private_data; + + if (!drv->heads) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -ENOTTY; + } + + drv_index = find_drv_index(h->ctlr, drv); + if (drv_index != CISS_MAX_LUN) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + + return snprintf(buf, 40, "%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X\n", + drv->uid[0], drv->uid[1], drv->uid[2], + drv->uid[3], drv->uid[4], drv->uid[5], + drv->uid[6], drv->uid[7], drv->uid[8], + drv->uid[9], drv->uid[10], drv->uid[11], + drv->uid[12], drv->uid[13], drv->uid[14], + drv->uid[15]); + } + + printk(KERN_ERR "cciss: logical drive not found\n"); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -ENOENT; +} + +static ssize_t cciss_show_bus(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 20, "cciss\n"); +} + +static ssize_t cciss_show_lunid(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drv_dynamic *d; + drive_info_struct *drv; + ctlr_info_t *h; + unsigned long flags; + int drv_index; + + d = container_of(dev, struct drv_dynamic, dev); + spin_lock(&sysfs_lock); + if (!d->disk) { + spin_unlock(&sysfs_lock); + return -ENOENT; + } + + h = get_host(d->disk); + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -EBUSY; + } + + drv = d->disk->private_data; + + if (!drv->heads) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -ENOTTY; + } + + drv_index = find_drv_index(h->ctlr, drv); + if (drv_index != CISS_MAX_LUN) { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return snprintf(buf, 20, "%d\n", drv->LunID); + } + + printk(KERN_ERR "cciss: logical drive not found\n"); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + spin_unlock(&sysfs_lock); + return -ENOTTY; +} + +DEVICE_ATTR(raid_level, S_IRUGO | S_IWUSR, cciss_show_raid_level, NULL); +DEVICE_ATTR(disk_size, S_IRUGO | S_IWUSR, cciss_show_disk_size, NULL); +DEVICE_ATTR(usage_count, S_IRUGO | S_IWUSR, cciss_show_usage_count, NULL); +DEVICE_ATTR(vendor, S_IRUGO | S_IWUSR, cciss_show_vendor, NULL); +DEVICE_ATTR(model, S_IRUGO | S_IWUSR, cciss_show_model, NULL); +DEVICE_ATTR(rev, S_IRUGO | S_IWUSR, cciss_show_rev, NULL); +DEVICE_ATTR(unique_id, S_IRUGO | S_IWUSR, cciss_show_unique_id, NULL); +DEVICE_ATTR(bus, S_IRUGO | S_IWUSR, cciss_show_bus, NULL); +DEVICE_ATTR(lunid, S_IRUGO | S_IWUSR, cciss_show_lunid, NULL); + +static struct attribute *cciss_sysfs_attrs[] = { + &dev_attr_raid_level.attr, + &dev_attr_disk_size.attr, + &dev_attr_usage_count.attr, + &dev_attr_vendor.attr, + &dev_attr_model.attr, + &dev_attr_rev.attr, + &dev_attr_unique_id.attr, + &dev_attr_bus.attr, + &dev_attr_lunid.attr, + NULL + }; + +static struct attribute_group cciss_attrs = {.attrs = cciss_sysfs_attrs}; + +static void cciss_add_blk_sysfs_dev(drive_info_struct *drv, + struct gendisk* disk, + struct pci_dev *pdev, int disk_num) +{ + int r; + struct drv_dynamic *d = kzalloc(sizeof(struct drv_dynamic), GFP_KERNEL); + if (!d) + return; + disk->driverfs_dev = &d->dev; + d->dev.parent = &pdev->dev; + d->dev.release = (void (*)(struct device *))kfree; + sprintf(d->dev.bus_id, "disk%d", disk_num); + d->dev.driver_data = "cciss"; + if (device_register(&d->dev)) { + put_device(&d->dev); + return; + } + r = sysfs_create_group(&d->dev.kobj, &cciss_attrs); + if (r) + return; + d->disk = disk; + drv->dev_info = &d->dev; +} + +static void cciss_remove_blk_sysfs_dev(struct gendisk *disk) +{ + drive_info_struct *drv = get_drv(disk); + struct drv_dynamic *d; + + if (!drv->dev_info) + return; + + d = container_of(drv->dev_info, struct drv_dynamic, dev); + spin_lock(&sysfs_lock); + sysfs_remove_group(&d->dev.kobj, &cciss_attrs); + d->disk = NULL; + spin_unlock(&sysfs_lock); + device_unregister(drv->dev_info); + drv->dev_info = NULL; +} #ifdef CONFIG_PROC_FS /* * Report information about this controller. */ -#define ENG_GIG 1000000000 -#define ENG_GIG_FACTOR (ENG_GIG/512) -static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", - "UNKNOWN" -}; static struct proc_dir_entry *proc_cciss; @@ -468,16 +933,6 @@ static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool) } } -static inline ctlr_info_t *get_host(struct gendisk *disk) -{ - return disk->queue->queuedata; -} - -static inline drive_info_struct *get_drv(struct gendisk *disk) -{ - return disk->private_data; -} - /* * Open. Make sure the device is really there. */ @@ -1378,6 +1833,10 @@ geo_inq: hba[ctlr]->drv[drv_index].block_size); h->drv[drv_index].queue = disk->queue; + cciss_sysfs_stat_inquiry(ctlr, drv_index, 1, + &h->drv[drv_index]); + cciss_add_blk_sysfs_dev(&h->drv[drv_index], disk, + h->pdev, drv_index); add_disk(disk); } @@ -1583,8 +2042,10 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, */ if (h->gendisk[0] != disk) { struct request_queue *q = disk->queue; - if (disk->flags & GENHD_FL_UP) + if (disk->flags & GENHD_FL_UP) { + cciss_remove_blk_sysfs_dev(disk); del_gendisk(disk); + } if (q) { blk_cleanup_queue(q); /* Set drv->queue to NULL so that we do not try @@ -3478,6 +3939,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, if (!drv->heads && j) continue; blk_queue_hardsect_size(q, drv->block_size); + cciss_sysfs_stat_inquiry(i, j, 1, drv); + cciss_add_blk_sysfs_dev(drv, disk, pdev, j); set_capacity(disk, drv->nr_blocks); add_disk(disk); j++; @@ -3574,8 +4037,10 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) if (disk) { struct request_queue *q = disk->queue; - if (disk->flags & GENHD_FL_UP) + if (disk->flags & GENHD_FL_UP) { + cciss_remove_blk_sysfs_dev(disk); del_gendisk(disk); + } if (q) blk_cleanup_queue(q); } diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index b70988d..d80b3e8 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -39,6 +39,11 @@ typedef struct _drive_info_struct *to prevent it from being opened or it's queue *from being started. */ + char vendor[9]; + char model[17]; + char rev[5]; + BYTE uid[16]; + struct device *dev_info; } drive_info_struct; #ifdef CONFIG_CISS_SCSI_TAPE @@ -146,6 +151,17 @@ struct ctlr_info #define CCISS_INTR_ON 1 #define CCISS_INTR_OFF 0 + +static inline ctlr_info_t *get_host(struct gendisk *disk) +{ + return disk->queue->queuedata; +} + +static inline drive_info_struct *get_drv(struct gendisk *disk) +{ + return disk->private_data; +} + /* Send the command to the hardware */ @@ -286,6 +302,11 @@ struct board_type { int nr_cmds; /* Max cmds this kind of ctlr can handle. */ }; +struct drv_dynamic { + struct device dev; /* should be the first member */ + struct gendisk *disk; +}; + #define CCISS_LOCK(i) (&hba[i]->lock) #endif /* CCISS_H */ - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html