fix scan_thread, sysfs stuff, LUN addressing problem
Subsystems (2)
cover fix scan_thread, sysfs stuff, LUN addressing problem
The following series cleans up the broken scan_thread code, allows triggering of the scan_thread via sysfs, dynamically allocates the struct device for each logical drive as needed instead of all at once at driver init time, fixes a bug in logical drive addressing (seen on MSA2012), and adds lunid, raid_level, and usage_count attributes in sysfs for each logical drive.
---
Andrew Patterson (3):
Allow triggering of rescan of logical drive topology via sysfs entry Use one scan thread per controller and fix hang during rmmod Remove sysfs entries for logical drives on driver cleanup.
Stephen M. Cameron (14):
Add usage_count attribute to each logical drive in /sys
Add a "raid_level" attribute to each logical drive in /sys
Add lunid attribute to each logical drive in /sys
Preserve all 8 bytes of LUN ID for logical drives.
Silence noisy per-disk messages output by cciss_read_capacity Fix excessive gendisk freeing bug on driver unload.
Fix usage_count check in rebuild_lun_table when triggered via sysfs. Clear all sysfs-exposed data for deleted logical drives. Handle special case for sysfs attributes of the first logical drive. Handle cases when cciss_add_disk fails.
Handle failure of blk_init_queue gracefully in cciss_add_disk. Rearrange logical drive sysfs code to make the "changing a disk" path work. Dynamically allocate struct device for each logical drive as needed. Remove some unused code in rebuild_lun_table()
.../ABI/testing/sysfs-bus-pci-devices-cciss | 28 + drivers/block/cciss.c | 551 +++++++++++++++----- drivers/block/cciss.h | 11 3 files changed, 461 insertions(+), 129 deletions(-)
Signature · 1 line
-- steve
PATCH 1/17 Remove sysfs entries for logical drives on driver cleanup.
From: Andrew Patterson <[email protected]>
Sysfs entries for logical drives need to be removed when a drive is deleted during driver cleanup.
---
drivers/block/cciss.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-)
drivers/block/cciss.c +4 -1
@@ -1977,7 +1977,6 @@ 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 ; } }
@@ -2118,6 +2117,7 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,* indicate that this element of the drive * array is free. */ +cciss_destroy_ld_sysfs_entry (drv);if (clear_all) {/* check to see if it was the last disk */
@@ -4141,6 +4141,9 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)if (q)blk_cleanup_queue (q); } +if (hba[i]->drv[j].raid_level !=-1 ) +cciss_destroy_ld_sysfs_entry (&hba[i]->drv[j]); + }#ifdef CONFIG_CISS_SCSI_TAPE
PATCH 2/17 Use one scan thread per controller and fix hang during rmmod
In reply to Stephen M. CameronFrom: Andrew Patterson <[email protected]>
Replace the use of one scan kthread per controller with one per driver. Use a queue to hold a list of controllers that need to be rescanned with routines to add and remove controllers from the queue.
Fix locking and completion handling to prevent a hang during rmmod.
---
drivers/block/cciss.c | 156 +++++++++++++++++++++++++++++++++++++++++++------ drivers/block/cciss.h | 7 ++ 2 files changed, 141 insertions(+), 22 deletions(-)
drivers/block/cciss.c +136 -20
@@ -39,6 +39,7 @@#include <linux/hdreg.h> #include <linux/spinlock.h> #include <linux/compat.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #include <asm/io.h>
@@ -155,6 +156,10 @@ static struct board_type products[] = {static ctlr_info_t *hba[MAX_CTLR ]; +static struct task_struct *cciss_scan_thread; +static DEFINE_MUTEX (scan_mutex); +static LIST_HEAD (scan_q); +static void do_cciss_request (struct request_queue *q);static irqreturn_t do_cciss_intr (int irq,void *dev_id);static int cciss_open (struct block_device *bdev,fmode_t mode);
@@ -3232,20 +3237,121 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)return IRQ_HANDLED ; } +/** +* add_to_scan_list() - add controller to rescan queue +* @h: Pointer to the controller. +* +* Adds the controller to the rescan queue if not already on the queue. +* +* returns 1 if added to the queue, 0 if skipped (could be on the +* queue already, or the controller could be initializing or shutting +* down). +**/ +static int add_to_scan_list (struct ctlr_info *h) +{ +struct ctlr_info *test_h; +int found =0 ; +int ret =0 ; + +if (h->busy_initializing) +return 0 ; + +if (!mutex_trylock (&h->busy_shutting_down)) +return 0 ; + +mutex_lock (&scan_mutex); +list_for_each_entry (test_h, &scan_q, scan_list) { +if (test_h == h) { + found =1 ; +break ; + } + } +if (!found && !h->busy_scanning) { +INIT_COMPLETION (h->scan_wait); +list_add_tail (&h->scan_list, &scan_q); + ret =1 ; + } +mutex_unlock (&scan_mutex); +mutex_unlock (&h->busy_shutting_down); + +return ret; +} + +/** +* remove_from_scan_list() - remove controller from rescan queue +* @h: Pointer to the controller. +* +* Removes the controller from the rescan queue if present. Blocks if +* the controller is currently conducting a rescan. +**/ +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) { +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) +wait_for_completion (&h->scan_wait); +} + +/** +* scan_thread() - kernel thread used to rescan controllers +* @data: Ignored. +* +* A kernel thread used scan for drive topology changes on +* controllers. The thread processes only one controller at a time +* using a queue. Controllers are added to the queue using +* add_to_scan_list() and removed from the queue either after done +* processing or using remove_from_scan_list(). +* +* returns 0. +**/ static int scan_thread (void *data) { -ctlr_info_t *h = data; -int rc; -DECLARE_COMPLETION_ONSTACK (wait); - h->rescan_wait = &wait; +struct ctlr_info *h; -for (;;) { - rc =wait_for_completion_interruptible (&wait); +while (1 ) { +set_current_state (TASK_INTERRUPTIBLE ); +schedule ();if (kthread_should_stop ())break ; -if (!rc) -rebuild_lun_table (h,0 ); + +while (1 ) { +mutex_lock (&scan_mutex); +if (list_empty (&scan_q)) { +mutex_unlock (&scan_mutex); +break ; + } + + h =list_entry (scan_q.next, + struct ctlr_info, + scan_list); +list_del (&h->scan_list); + h->busy_scanning =1 ; +mutex_unlock (&scan_mutex); + +if (h) { +rebuild_lun_table (h,0 ); +complete_all (&h->scan_wait); +mutex_lock (&scan_mutex); + h->busy_scanning =0 ; +mutex_unlock (&scan_mutex); + } + } } +return 0 ; }
@@ -3268,8 +3374,8 @@ 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); -if (h->rescan_wait) -complete (h->rescan_wait); +add_to_scan_list (h); +wake_up_process (cciss_scan_thread);return 1 ;break ;case POWER_OR_RESET :
@@ -3918,6 +4024,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, hba[i]->busy_initializing =1 ;INIT_HLIST_HEAD (&hba[i]->cmpQ);INIT_HLIST_HEAD (&hba[i]->reqQ); +mutex_init (&hba[i]->busy_shutting_down);if (cciss_pci_init (hba[i], pdev) !=0 ) goto clean0;
@@ -3926,6 +4033,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, hba[i]->ctlr = i; hba[i]->pdev = pdev; +init_completion (&hba[i]->scan_wait); +if (cciss_create_hba_sysfs_entry (hba[i])) goto clean0;
@@ -4034,14 +4143,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, hba[i]->cciss_max_sectors =2048 ; - hba[i]->busy_initializing =0 ; -rebuild_lun_table (hba[i],1 ); - hba[i]->cciss_scan_thread =kthread_run (scan_thread, hba[i], -"cciss_scan%02d" , i); -if (IS_ERR (hba[i]->cciss_scan_thread)) -return PTR_ERR (hba[i]->cciss_scan_thread); - + hba[i]->busy_initializing =0 ;return 1 ; clean4:
@@ -4125,8 +4228,9 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)return ; } -kthread_stop (hba[i]->cciss_scan_thread); +mutex_lock (&hba[i]->busy_shutting_down); +remove_from_scan_list (hba[i]);remove_proc_entry (hba[i]->devname, proc_cciss);unregister_blkdev (hba[i]->major, hba[i]->devname);
@@ -4173,6 +4277,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)pci_release_regions (pdev);pci_set_drvdata (pdev,NULL );cciss_destroy_hba_sysfs_entry (hba[i]); +mutex_unlock (&hba[i]->busy_shutting_down);free_hba (i); }
@@ -4205,15 +4310,25 @@ static int __init cciss_init(void)if (err)return err; +/* Start the scan thread */ + cciss_scan_thread =kthread_run (scan_thread,NULL ,"cciss_scan" ); +if (IS_ERR (cciss_scan_thread)) { + err =PTR_ERR (cciss_scan_thread); + goto err_bus_unregister; + } +/* Register for our PCI devices */ err =pci_register_driver (&cciss_pci_driver);if (err) - goto err_bus_register; + goto err_thread_stop;return 0 ; -err_bus_register: +err_thread_stop: +kthread_stop (cciss_scan_thread); +err_bus_unregister:bus_unregister (&cciss_bus_type); +return err; }
@@ -4230,6 +4345,7 @@ static void __exit cciss_cleanup(void)cciss_remove_one (hba[i]->pdev); } } +kthread_stop (cciss_scan_thread);remove_proc_entry ("driver/cciss" ,NULL );bus_unregister (&cciss_bus_type); }
drivers/block/cciss.h +5 -2
@@ -2,6 +2,7 @@#define CCISS_H #include <linux/genhd.h> +#include <linux/mutex.h> #include "cciss_cmd.h"
@@ -108,6 +109,8 @@ struct ctlr_infoint nr_frees;int busy_configuring;int busy_initializing; +int busy_scanning; +struct mutex busy_shutting_down;/* This element holds the zero based queue number of the last * queue to be started. It is used for fairness.
@@ -122,8 +125,8 @@ struct ctlr_info/* and saved for later processing */ #endif unsigned char alive; -struct completion *rescan_wait; -struct task_struct *cciss_scan_thread; +struct list_head scan_list; +struct completion scan_wait;struct device dev; };
PATCH 3/17 Allow triggering of rescan of logical drive topology via sysfs entry
In reply to Stephen M. CameronFrom: Andrew Patterson <[email protected]>
Added /sys/bus/pci/devices/<dev>/ccissX/rescan sysfs entry used to kick off a rescan that discovers logical drive topology changes.
---
.../ABI/testing/sysfs-bus-pci-devices-cciss | 7 ++++ drivers/block/cciss.c | 36 ++++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-)
Documentation/ABI/testing/sysfs-bus-pci-devices-cciss +7 -0
@@ -31,3 +31,10 @@ Date: March 2009 Kernel Version: 2.6.30 Contact: [email protected] Description: A symbolic link to /sys/block/cciss!cXdY + +Where: /sys/bus/pci/devices/<dev>/ccissX/rescan +Date: August 2009 +Kernel Version: 2.6.31 +Contact: [email protected] +Description: Kicks of a rescan of the controller to discover logical + drive topology changes.
drivers/block/cciss.c +33 -3
@@ -194,6 +194,7 @@ static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,static int process_sendcmd_error (ctlr_info_t *h,CommandList_struct *c);static void fail_all_cmds (unsigned long ctlr); +static int add_to_scan_list (struct ctlr_info *h);static int scan_thread (void *data);static int check_for_unit_attention (ctlr_info_t *h,CommandList_struct *c);
@@ -459,9 +460,19 @@ static void __devinit cciss_procinit(int i)#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 host_store_rescan (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +struct ctlr_info *h =to_hba (dev); + +add_to_scan_list (h); +wake_up_process (cciss_scan_thread); +wait_for_completion_interruptible (&h->scan_wait); + +return count; +} +DEVICE_ATTR (rescan,S_IWUSR ,NULL , host_store_rescan); static ssize_t dev_show_unique_id(struct device *dev, struct device_attribute *attr,
@@ -565,6 +576,25 @@ static ssize_t dev_show_rev(struct device *dev, }DEVICE_ATTR (rev,S_IRUGO , dev_show_rev,NULL ); +static struct attribute *cciss_host_attrs[] = { + &dev_attr_rescan.attr, +NULL +}; + +static struct attribute_group cciss_host_attr_group = { + .attrs = cciss_host_attrs, +}; + +static struct attribute_group *cciss_host_attr_groups[] = { + &cciss_host_attr_group, +NULL +}; + +static struct device_type cciss_host_type = { + .name ="cciss_host" , + .groups = cciss_host_attr_groups, +}; +static struct attribute *cciss_dev_attrs[] = { &dev_attr_unique_id.attr, &dev_attr_model.attr,
PATCH 4/17 Remove some unused code in rebuild_lun_table()
In reply to Stephen M. CameronRemove some unused code in rebuild_lun_table()
---
drivers/block/cciss.c | 8 -------- 1 files changed, 0 insertions(+), 8 deletions(-)
drivers/block/cciss.c +0 -8
@@ -1707,7 +1707,6 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)unsigned long flags =0 ;int ret =0 ;drive_info_struct *drvinfo; -int was_only_controller_node;/* Get information about the disk and modify the driver structure */ inq_buff =kmalloc (sizeof (InquiryData_struct),GFP_KERNEL );
@@ -1715,13 +1714,6 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)if (inq_buff ==NULL || drvinfo ==NULL ) goto mem_msg; -/* See if we're trying to update the "controller node" -* this will happen the when the first logical drive gets -* created by ACU. -*/ - was_only_controller_node = (drv_index ==0 && - h->drv[0 ].raid_level ==-1 ); -/* 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,
PATCH 5/17 Dynamically allocate struct device for each logical drive as needed.
In reply to Stephen M. CameronDynamically allocate struct device for each logical drive as needed instead of allocating the maximum we would ever need at driver init time.
---
drivers/block/cciss.c | 98 ++++++++++++++++++++++++++++++++++++------------- drivers/block/cciss.h | 2 + 2 files changed, 73 insertions(+), 27 deletions(-)
drivers/block/cciss.c +72 -26
@@ -197,6 +197,8 @@ static void fail_all_cmds(unsigned long ctlr);static int add_to_scan_list (struct ctlr_info *h);static int scan_thread (void *data);static int check_for_unit_attention (ctlr_info_t *h,CommandList_struct *c); +static void cciss_hba_release (struct device *dev); +static void cciss_device_release (struct device *dev);#ifdef CONFIG_PROC_FS static void cciss_procinit (int i);
@@ -458,7 +460,6 @@ static void __devinit cciss_procinit(int i)#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 ssize_t host_store_rescan(struct device *dev, struct device_attribute *attr,
@@ -478,8 +479,8 @@ 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); + drive_info_struct *drv = dev_get_drvdata(dev); +struct ctlr_info *h =to_hba (drv->dev->parent);__u8 sn[16 ];unsigned long flags;int ret =0 ;
@@ -508,8 +509,8 @@ 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); + drive_info_struct *drv = dev_get_drvdata(dev); +struct ctlr_info *h =to_hba (drv->dev->parent);char vendor[VENDOR_LEN +1 ];unsigned long flags;int ret =0 ;
@@ -532,8 +533,8 @@ 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); + drive_info_struct *drv = dev_get_drvdata(dev); +struct ctlr_info *h =to_hba (drv->dev->parent);char model[MODEL_LEN +1 ];unsigned long flags;int ret =0 ;
@@ -556,8 +557,8 @@ 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); + drive_info_struct *drv = dev_get_drvdata(dev); +struct ctlr_info *h =to_hba (drv->dev->parent);char rev[REV_LEN +1 ];unsigned long flags;int ret =0 ;
@@ -593,6 +594,7 @@ static struct attribute_group *cciss_host_attr_groups[] = {static struct device_type cciss_host_type = { .name ="cciss_host" , .groups = cciss_host_attr_groups, + .release = cciss_hba_release, };static struct attribute *cciss_dev_attrs[] = {
@@ -615,12 +617,24 @@ static struct attribute_group *cciss_dev_attr_groups[] = {static struct device_type cciss_dev_type = { .name ="cciss_device" , .groups = cciss_dev_attr_groups, + .release = cciss_device_release, };static struct bus_type cciss_bus_type = { .name ="cciss" , }; +/* +* cciss_hba_release is called when the reference count +* of h->dev goes to zero. +*/ +static void cciss_hba_release (struct device *dev) +{ +/* +* nothing to do, but need this to avoid a warning +* about not having a release handler from lib/kref.c. +*/ +}/* * Initialize sysfs entry for each controller. This sets up and registers
@@ -644,6 +658,15 @@ static int cciss_create_hba_sysfs_entry(struct ctlr_info *h)static void cciss_destroy_hba_sysfs_entry (struct ctlr_info *h) {device_del (&h->dev); +put_device (&h->dev);/* final put. */ +} + +/* cciss_device_release is called when the reference count +* of h->drv[x].dev goes to zero. +*/ +static void cciss_device_release (struct device *dev) +{ +kfree (dev); }/*
@@ -652,24 +675,33 @@ static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h)* /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, +static long cciss_create_ld_sysfs_entry (struct ctlr_info *h,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); +struct device *dev; + + dev =kzalloc (sizeof (*dev),GFP_KERNEL ); +if (!dev) +return -ENOMEM ; +device_initialize (dev); + dev->type = &cciss_dev_type; + dev->bus = &cciss_bus_type; +dev_set_name (dev,"c%dd%d" , h->ctlr, drv_index); + dev->parent = &h->dev; + h->drv[drv_index].dev = dev; +dev_set_drvdata (dev, &h->drv[drv_index]); +return device_add (dev); }/* * Remove sysfs entries for a logical drive. */ -static void cciss_destroy_ld_sysfs_entry (drive_info_struct *drv) +static void cciss_destroy_ld_sysfs_entry (struct ctlr_info *h,int drv_index) { -device_del (&drv->dev); +struct device *dev = h->drv[drv_index].dev; +device_del (dev); +put_device (dev);/* the "final" put. */ + h->drv[drv_index].dev =NULL ; }/*
@@ -1650,7 +1682,10 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq,return ; } -static void cciss_add_disk (ctlr_info_t *h,struct gendisk *disk, +/* +* cciss_add_disk sets up the block device queue for a logical drive +*/ +static int cciss_add_disk (ctlr_info_t *h,struct gendisk *disk,int drv_index) { disk->queue =blk_init_queue (do_cciss_request, &h->lock);
@@ -1658,8 +1693,12 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk, disk->major = h->major; disk->first_minor = drv_index <<NWD_SHIFT ; disk->fops = &cciss_fops; +if (h->drv[drv_index].dev ==NULL ) { +if (cciss_create_ld_sysfs_entry (h, drv_index)) + goto cleanup_queue; + } disk->private_data = &h->drv[drv_index]; - disk->driverfs_dev = &h->drv[drv_index].dev; + disk->driverfs_dev = h->drv[drv_index].dev;/* Set up queue information */ blk_queue_bounce_limit (disk->queue, h->pdev->dma_mask);
@@ -1685,6 +1724,12 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,wmb (); h->drv[drv_index].queue = disk->queue;add_disk (disk); +return 0 ; + +cleanup_queue: +blk_cleanup_queue (disk->queue); + disk->queue =NULL ; +return -1 ; }/* This function will check the usage_count of the drive to be updated/added.
@@ -1870,7 +1915,7 @@ 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)) +if (cciss_create_ld_sysfs_entry (h, drv_index)) goto err_free_disk;/* Don't need to mark this busy because nobody */
@@ -2144,7 +2189,7 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,* indicate that this element of the drive * array is free. */ -cciss_destroy_ld_sysfs_entry (drv); +cciss_destroy_ld_sysfs_entry (h, drv_index);if (clear_all) {/* check to see if it was the last disk */
@@ -4267,8 +4312,9 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)if (q)blk_cleanup_queue (q); } -if (hba[i]->drv[j].raid_level !=-1 ) -cciss_destroy_ld_sysfs_entry (&hba[i]->drv[j]); +if (hba[i]->drv[j].dev !=NULL && + (j ==0 || hba[i]->drv[j].raid_level !=-1 )) +cciss_destroy_ld_sysfs_entry (hba[i], j); }
@@ -4344,7 +4390,7 @@ static int __init cciss_init(void)if (err) goto err_thread_stop; -return 0 ; +return err; err_thread_stop:kthread_stop (cciss_scan_thread);
drivers/block/cciss.h +1 -1
@@ -45,7 +45,7 @@ typedef struct _drive_info_struct* to prevent it from being opened or it's * queue from being started. */ -struct device dev; +struct device *dev;__u8 serial_no[16 ];/* from inquiry page 0x83, * not necc. null terminated. */
PATCH 6/17 Rearrange logical drive sysfs code to make the "changing a disk" path work.
In reply to Stephen M. CameronRearrange logical drive sysfs code to make the "changing a disk" path work.
---
drivers/block/cciss.c | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-)
drivers/block/cciss.c +10 -10
@@ -1915,9 +1915,10 @@ 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, drv_index)) - goto err_free_disk; - +if (h->drv[drv_index].dev ==NULL ) { +if (cciss_create_ld_sysfs_entry (h, drv_index)) + goto err_free_disk; + }/* Don't need to mark this busy because nobody */ /* else knows about this disk yet to contend */ /* for access to it. */
@@ -2144,8 +2145,10 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,*/ if (h->gendisk[0 ] != disk) {struct request_queue *q = disk->queue; -if (disk->flags &GENHD_FL_UP ) +if (disk->flags &GENHD_FL_UP ) { +cciss_destroy_ld_sysfs_entry (h, drv_index);del_gendisk (disk); + }if (q) {blk_cleanup_queue (q);/* Set drv->queue to NULL so that we do not try
@@ -2189,7 +2192,6 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,* indicate that this element of the drive * array is free. */ -cciss_destroy_ld_sysfs_entry (h, drv_index);if (clear_all) {/* check to see if it was the last disk */
@@ -4307,15 +4309,13 @@ 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_destroy_ld_sysfs_entry (hba[i], j);del_gendisk (disk); + }if (q)blk_cleanup_queue (q); } -if (hba[i]->drv[j].dev !=NULL && - (j ==0 || hba[i]->drv[j].raid_level !=-1 )) -cciss_destroy_ld_sysfs_entry (hba[i], j); - }#ifdef CONFIG_CISS_SCSI_TAPE
PATCH 7/17 Handle failure of blk_init_queue gracefully in cciss_add_disk.
In reply to Stephen M. CameronHandle failure of blk_init_queue gracefully in cciss_add_disk.
---
drivers/block/cciss.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
drivers/block/cciss.c +3 -0
@@ -1689,6 +1689,8 @@ static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk, int drv_index) { disk->queue =blk_init_queue (do_cciss_request, &h->lock); +if (!disk->queue) + goto init_queue_failure;sprintf (disk->disk_name,"cciss/c%dd%d" , h->ctlr, drv_index); disk->major = h->major; disk->first_minor = drv_index <<NWD_SHIFT ;
@@ -1729,6 +1731,7 @@ static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk, cleanup_queue:blk_cleanup_queue (disk->queue); disk->queue =NULL ; +init_queue_failure:return -1 ; }
PATCH 8/17 Handle cases when cciss_add_disk fails.
In reply to Stephen M. CameronHandle cases when cciss_add_disk fails.
---
drivers/block/cciss.c | 35 +++++++++++++++++++++++++---------- 1 files changed, 25 insertions(+), 10 deletions(-)
drivers/block/cciss.c +25 -10
@@ -199,6 +199,7 @@ static int scan_thread(void *data);static int check_for_unit_attention (ctlr_info_t *h,CommandList_struct *c);static void cciss_hba_release (struct device *dev);static void cciss_device_release (struct device *dev); +static void cciss_free_gendisk (ctlr_info_t *h,int drv_index);#ifdef CONFIG_PROC_FS static void cciss_procinit (int i);
@@ -1855,8 +1856,14 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)* (raid_leve == -1) then we want to update the * logical drive's information. */ -if (drv_index || first_time) -cciss_add_disk (h, disk, drv_index); +if (drv_index || first_time) { +if (cciss_add_disk (h, disk, drv_index) !=0 ) { +cciss_free_gendisk (h, drv_index); +printk (KERN_WARNING "cciss:%d could not update " +"disk %d\n" , h->ctlr, drv_index); + --h->num_luns; + } + } freeret:kfree (inq_buff);
@@ -1890,6 +1897,12 @@ static int cciss_find_free_drive_index(int ctlr, int controller_node)return -1 ; } +static void cciss_free_gendisk (ctlr_info_t *h,int drv_index) +{ +put_disk (h->gendisk[drv_index]); + h->gendisk[drv_index] =NULL ; +} +/* cciss_add_gendisk finds a free hba[]->drv structure * and allocates a gendisk if needed, and sets the lunid * in the drvinfo structure. It returns the index into
@@ -1930,8 +1943,7 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node)return drv_index; err_free_disk: -put_disk (h->gendisk[drv_index]); - h->gendisk[drv_index] =NULL ; +cciss_free_gendisk (h, drv_index);return -1 ; }
@@ -1949,11 +1961,8 @@ static void cciss_add_controller_node(ctlr_info_t *h)return ; drv_index =cciss_add_gendisk (h,0 ,1 ); -if (drv_index ==-1 ) { -printk (KERN_WARNING "cciss%d: could not " -"add disk 0.\n" , h->ctlr); -return ; - } +if (drv_index ==-1 ) + goto error; h->drv[drv_index].block_size =512 ; h->drv[drv_index].nr_blocks =0 ; h->drv[drv_index].heads =0 ;
@@ -1962,7 +1971,13 @@ static void cciss_add_controller_node(ctlr_info_t *h) h->drv[drv_index].raid_level =-1 ;memset (h->drv[drv_index].serial_no,0 ,16 ); disk = h->gendisk[drv_index]; -cciss_add_disk (h, disk, drv_index); +if (cciss_add_disk (h, disk, drv_index) ==0 ) +return ; +cciss_free_gendisk (h, drv_index); +error: +printk (KERN_WARNING "cciss%d: could not " +"add disk 0.\n" , h->ctlr); +return ; }/* This function will add and remove logical drives from the Logical
PATCH 9/17 Handle special case for sysfs attributes of the first logical drive.
In reply to Stephen M. CameronFor c0dx where x is not 0, we handle deletion and addition simply, but for c0d0, there is the special case that even when there's no disk, the device node exists so that the controller may be accessed. So, for c0d0, we only create the sysfs entries once, when a controller is added, and only remove them once, when a controller is being taken down.
---
drivers/block/cciss.c | 18 ++++++++++++++---- 1 files changed, 14 insertions(+), 4 deletions(-)
drivers/block/cciss.c +14 -4
@@ -681,6 +681,10 @@ static long cciss_create_ld_sysfs_entry(struct ctlr_info *h, {struct device *dev; +/* Special case for c*d0, we only create it once. */ +if (drv_index ==0 && h->drv[drv_index].dev !=NULL ) +return 0 ; + dev =kzalloc (sizeof (*dev),GFP_KERNEL );if (!dev)return -ENOMEM ;
@@ -697,9 +701,15 @@ static long cciss_create_ld_sysfs_entry(struct ctlr_info *h,/* * Remove sysfs entries for a logical drive. */ -static void cciss_destroy_ld_sysfs_entry (struct ctlr_info *h,int drv_index) +static void cciss_destroy_ld_sysfs_entry (struct ctlr_info *h,int drv_index, +int ctlr_exiting) {struct device *dev = h->drv[drv_index].dev; + +/* special case for c*d0, we only destroy it on controller exit */ +if (drv_index ==0 && !ctlr_exiting) +return ; +device_del (dev);put_device (dev);/* the "final" put. */ h->drv[drv_index].dev =NULL ;
@@ -1919,6 +1929,7 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node) drv_index =cciss_find_free_drive_index (h->ctlr, controller_node);if (drv_index ==-1 )return -1 ; +/*Check if the gendisk needs to be allocated */ if (!h->gendisk[drv_index]) { h->gendisk[drv_index] =
@@ -2164,7 +2175,7 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,if (h->gendisk[0 ] != disk) {struct request_queue *q = disk->queue;if (disk->flags &GENHD_FL_UP ) { -cciss_destroy_ld_sysfs_entry (h, drv_index); +cciss_destroy_ld_sysfs_entry (h, drv_index,0 );del_gendisk (disk); }if (q) {
@@ -2210,7 +2221,6 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,* indicate that this element of the drive * array is free. */ -if (clear_all) {/* check to see if it was the last disk */ if (drv == h->drv + h->highest_lun) {
@@ -4328,7 +4338,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)struct request_queue *q = disk->queue;if (disk->flags &GENHD_FL_UP ) { -cciss_destroy_ld_sysfs_entry (hba[i], j); +cciss_destroy_ld_sysfs_entry (hba[i], j,1 );del_gendisk (disk); }if (q)
PATCH 10/17 Clear all sysfs-exposed data for deleted logical drives.
In reply to Stephen M. CameronWhen removing a logical drive, clear all the information that is now exposed by sysfs (e.g. vendor, model, serial number.)
---
drivers/block/cciss.c | 31 +++++++++++++++++++++---------- 1 files changed, 21 insertions(+), 10 deletions(-)
drivers/block/cciss.c +21 -10
@@ -2133,6 +2133,25 @@ mem_msg: goto freeret; } +static void cciss_clear_drive_info (drive_info_struct *drive_info) +{ +/* zero out the disk size info */ + drive_info->nr_blocks =0 ; + drive_info->block_size =0 ; + drive_info->heads =0 ; + drive_info->sectors =0 ; + drive_info->cylinders =0 ; + drive_info->raid_level =-1 ; +memset (drive_info->serial_no,0 ,sizeof (drive_info->serial_no)); +memset (drive_info->model,0 ,sizeof (drive_info->model)); +memset (drive_info->rev,0 ,sizeof (drive_info->rev)); +memset (drive_info->vendor,0 ,sizeof (drive_info->vendor)); +/* +* don't clear the LUNID though, we need to remember which +* one this one is. +*/ +} +/* This function will deregister the disk and it's queue from the * kernel. It must be called with the controller lock held and the * drv structures busy_configuring flag set. It's parameters are:
@@ -2211,16 +2230,8 @@ static int deregister_disk(ctlr_info_t *h, int drv_index, } --h->num_luns; -/* zero out the disk size info */ - drv->nr_blocks =0 ; - drv->block_size =0 ; - drv->heads =0 ; - drv->sectors =0 ; - drv->cylinders =0 ; - drv->raid_level =-1 ;/* This can be used as a flag variable to -* indicate that this element of the drive -* array is free. -*/ +cciss_clear_drive_info (drv); +if (clear_all) {/* check to see if it was the last disk */ if (drv == h->drv + h->highest_lun) {
PATCH 11/17 Fix usage_count check in rebuild_lun_table when triggered via sysfs.
In reply to Stephen M. CameronWhen rebuild_lun_table is reached via sysfs, the usage count that is checked prior to messing with c0d0 has different constraints (must be zero) than if rebuild_lun_table is reached via ioctl (must be one.) Fix rebuild_lun_table to take that into account.
---
drivers/block/cciss.c | 33 +++++++++++++++++++++------------ 1 files changed, 21 insertions(+), 12 deletions(-)
drivers/block/cciss.c +21 -12
@@ -169,9 +169,9 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,static int cciss_getgeo (struct block_device *bdev,struct hd_geometry *geo);static int cciss_revalidate (struct gendisk *disk); -static int rebuild_lun_table (ctlr_info_t *h,int first_time); +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 clear_all,int via_ioctl);static void cciss_read_capacity (int ctlr,int logvol,int withirq,sector_t *total_size,unsigned int *block_size);
@@ -1210,7 +1210,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,case CCISS_DEREGDISK :case CCISS_REGNEWD :case CCISS_REVALIDVOLS : -return rebuild_lun_table (host,0 ); +return rebuild_lun_table (host,0 ,1 );case CCISS_GETLUNINFO :{LogvolInfo_struct luninfo;
@@ -1756,7 +1756,8 @@ init_queue_failure:* is also the controller node. Any changes to disk 0 will show up on * the next reboot. */ -static void cciss_update_drive_info (int ctlr,int drv_index,int first_time) +static void cciss_update_drive_info (int ctlr,int drv_index,int first_time, +int via_ioctl) {ctlr_info_t *h = hba[ctlr];struct gendisk *disk;
@@ -1834,7 +1835,7 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)* which keeps the interrupt handler from starting * the queue. */ - ret =deregister_disk (h, drv_index,0 ); + ret =deregister_disk (h, drv_index,0 , via_ioctl); h->drv[drv_index].busy_configuring =0 ; }
@@ -1999,7 +2000,8 @@ error:* INPUT * h = The controller to perform the operations on */ -static int rebuild_lun_table (ctlr_info_t *h,int first_time) +static int rebuild_lun_table (ctlr_info_t *h,int first_time, +int via_ioctl) {int ctlr = h->ctlr;int num_luns;
@@ -2078,7 +2080,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)spin_lock_irqsave (CCISS_LOCK (h->ctlr), flags); h->drv[i].busy_configuring =1 ;spin_unlock_irqrestore (CCISS_LOCK (h->ctlr), flags); - return_code =deregister_disk (h, i,1 ); + return_code =deregister_disk (h, i,1 , via_ioctl); h->drv[i].busy_configuring =0 ; } }
@@ -2116,7 +2118,8 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)if (drv_index ==-1 ) goto freeret; } -cciss_update_drive_info (ctlr, drv_index, first_time); +cciss_update_drive_info (ctlr, drv_index, first_time, + via_ioctl); }/* end for */ freeret:
@@ -2166,9 +2169,15 @@ static void cciss_clear_drive_info(drive_info_struct *drive_info)* the disk in preparation for re-adding it. In this case * the highest_lun should be left unchanged and the LunID * should not be cleared. +* via_ioctl +* This indicates whether we've reached this path via ioctl. +* This affects the maximum usage count allowed for c0d0 to be messed with. +* If this path is reached via ioctl(), then the max_usage_count will +* be 1, as the process calling ioctl() has got to have the device open. +* If we get here via sysfs, then the max usage count will be zero. */ static int deregister_disk (ctlr_info_t *h,int drv_index, -int clear_all) +int clear_all,int via_ioctl) {int i;struct gendisk *disk;
@@ -2182,7 +2191,7 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,/* make sure logical volume is NOT is use */ if (clear_all || (h->gendisk[0 ] == disk)) { -if (drv->usage_count >1 ) +if (drv->usage_count > via_ioctl)return -EBUSY ; }else if (drv->usage_count >0 )return -EBUSY ;
@@ -3451,7 +3460,7 @@ static int scan_thread(void *data)mutex_unlock (&scan_mutex);if (h) { -rebuild_lun_table (h,0 ); +rebuild_lun_table (h,0 ,0 );complete_all (&h->scan_wait);mutex_lock (&scan_mutex); h->busy_scanning =0 ;
@@ -4251,7 +4260,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, hba[i]->cciss_max_sectors =2048 ; -rebuild_lun_table (hba[i],1 ); +rebuild_lun_table (hba[i],1 ,0 ); hba[i]->busy_initializing =0 ;return 1 ;
PATCH 12/17 Fix excessive gendisk freeing bug on driver unload.
In reply to Stephen M. CameronFix bug that free_hba was calling put_disk for all gendisk[] pointers -- all 1024 of them -- regardless of whether the were used or not (NULL). This bug could cause rmmod to oops if logical drives had been deleted during the driver's lifetime.
---
drivers/block/cciss.c | 15 ++++++++------- 1 files changed, 8 insertions(+), 7 deletions(-)
drivers/block/cciss.c +8 -7
@@ -3892,15 +3892,16 @@ Enomem:return -1 ; } -static void free_hba (int i) +static void free_hba (int n) { -ctlr_info_t *p = hba[i]; -int n; +ctlr_info_t *h = hba[n]; +int i; - hba[i] =NULL ; -for (n =0 ; n <CISS_MAX_LUN ; n++) -put_disk (p->gendisk[n]); -kfree (p); + hba[n] =NULL ; +for (i =0 ; i < h->highest_lun +1 ; i++) +if (h->gendisk[i] !=NULL ) +put_disk (h->gendisk[i]); +kfree (h); }/* Send a message CDB to the firmware. */
PATCH 13/17 Silence noisy per-disk messages output by cciss_read_capacity
In reply to Stephen M. CameronSilence noisy per-disk messages output by cciss_read_capacity
---
drivers/block/cciss.c | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-)
drivers/block/cciss.c +0 -5
@@ -2601,8 +2601,6 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, }else {/* Get geometry failed */ printk (KERN_WARNING "cciss: reading geometry failed\n" ); } -printk (KERN_INFO " heads=%d, sectors=%d, cylinders=%d\n\n" , - drv->heads, drv->sectors, drv->cylinders); } static void
@@ -2636,9 +2634,6 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, *total_size =0 ; *block_size =BLOCK_SIZE ; } -if (*total_size !=0 ) -printk (KERN_INFO " blocks= %llu block_size= %d\n" , - (unsigned long long )*total_size+1 , *block_size);kfree (buf); }
PATCH 14/17 Preserve all 8 bytes of LUN ID for logical drives.
In reply to Stephen M. CameronPreserve all 8 bytes of the LunID field returned
by CCISS_REPORT_LOGICAL instead of only saving 4 bytes. This fixes a bug with logical volume addressing encountered on an MSA2012.
---
drivers/block/cciss.c | 48 ++++++++++++++++++++++++------------------------ drivers/block/cciss.h | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-)
drivers/block/cciss.c +24 -24
@@ -845,7 +845,8 @@ static int cciss_open(struct block_device *bdev, fmode_t mode)if (MINOR (bdev->bd_dev) &0x0f ) {return -ENXIO ;/* if it is, make sure we have a LUN ID */ - }else if (drv->LunID ==0 ) { + }else if (memcmp (drv->LunID,CTLR_LUNID , +sizeof (drv->LunID))) {return -ENXIO ; } }
@@ -1215,7 +1216,8 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,case CCISS_GETLUNINFO :{LogvolInfo_struct luninfo; - luninfo.LunID = drv->LunID; +memcpy (&luninfo.LunID, drv->LunID, +sizeof (luninfo.LunID)); luninfo.num_opens = drv->usage_count; luninfo.num_parts =0 ; if (copy_to_user(argp, &luninfo,
@@ -1610,13 +1612,11 @@ 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) +static inline 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 ; +memcpy (scsi3addr, h->drv[log_unit].LunID, +sizeof (h->drv[log_unit].LunID)); }/* This function gets the SCSI vendor, model, and revision of a logical drive
@@ -1923,7 +1923,8 @@ static void cciss_free_gendisk(ctlr_info_t *h, int drv_index)* a means to talk to the controller in case no logical * drives have yet been configured. */ -static int cciss_add_gendisk (ctlr_info_t *h,__u32 lunid,int controller_node) +static int cciss_add_gendisk (ctlr_info_t *h,unsigned char lunid[], +int controller_node) {int drv_index;
@@ -1942,7 +1943,8 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node)return -1 ; } } - h->drv[drv_index].LunID = lunid; +memcpy (h->drv[drv_index].LunID, lunid, +sizeof (h->drv[drv_index].LunID));if (h->drv[drv_index].dev ==NULL ) {if (cciss_create_ld_sysfs_entry (h, drv_index)) goto err_free_disk;
@@ -1972,7 +1974,7 @@ static void cciss_add_controller_node(ctlr_info_t *h)if (h->gendisk[0 ] !=NULL )/* already did this? Then bail. */ return ; - drv_index =cciss_add_gendisk (h,0 ,1 ); + drv_index =cciss_add_gendisk (h,CTLR_LUNID ,1 );if (drv_index ==-1 ) goto error; h->drv[drv_index].block_size =512 ;
@@ -2011,7 +2013,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time,int i;int drv_found;int drv_index =0 ; -__u32 lunid =0 ; +unsigned char lunid[8 ] =CTLR_LUNID ;unsigned long flags;if (!capable (CAP_SYS_RAWIO ))
@@ -2068,9 +2070,9 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time,continue ;for (j =0 ; j < num_luns; j++) { -memcpy (&lunid, &ld_buff->LUN[j][0 ],4 ); - lunid =le32_to_cpu (lunid); -if (h->drv[i].LunID == lunid) { +memcpy (lunid, &ld_buff->LUN[j][0 ],sizeof (lunid)); +if (memcmp (h->drv[i].LunID, lunid, +sizeof (lunid)) ==0 ) { drv_found =1 ;break ; }
@@ -2095,9 +2097,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time, drv_found =0 ; -memcpy (&lunid, &ld_buff->LUN[i][0 ],4 ); - lunid =le32_to_cpu (lunid); - +memcpy (lunid, &ld_buff->LUN[i][0 ],sizeof (lunid));/* Find if the LUN is already in the drive array * of the driver. If so then update its info * if not in use. If it does not exist then find
@@ -2105,7 +2105,8 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time,*/ for (j =0 ; j <= h->highest_lun; j++) {if (h->drv[j].raid_level !=-1 && - h->drv[j].LunID == lunid) { +memcmp (h->drv[j].LunID, lunid, +sizeof (h->drv[j].LunID)) ==0 ) { drv_index = j; drv_found =1 ;break ;
@@ -2253,8 +2254,7 @@ static int deregister_disk(ctlr_info_t *h, int drv_index, } h->highest_lun = newhighest; } - - drv->LunID =0 ; +memset (drv->LunID,0 ,sizeof (drv->LunID)); }return 0 ; }
@@ -2685,7 +2685,8 @@ static int cciss_revalidate(struct gendisk *disk)InquiryData_struct *inq_buff =NULL ;for (logvol =0 ; logvol <CISS_MAX_LUN ; logvol++) { -if (h->drv[logvol].LunID == drv->LunID) { +if (memcmp (h->drv[logvol].LunID, drv->LunID, +sizeof (drv->LunID)) ==0 ) {FOUND =1 ;break ; }
@@ -3170,8 +3171,7 @@ static void do_cciss_request(struct request_queue *q)/* 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. */ - c->Header.LUN.LogDev.VolId = drv->LunID; - c->Header.LUN.LogDev.Mode =1 ; +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.Type.Attribute =ATTR_SIMPLE ;
drivers/block/cciss.h +1 -1
@@ -30,7 +30,7 @@ struct access_method { }; typedef struct _drive_info_struct { - __u32 LunID; + unsigned char LunID[8]; int usage_count; struct request_queue *queue; sector_t nr_blocks;
PATCH 15/17 Add lunid attribute to each logical drive in /sys
In reply to Stephen M. CameronAdd lunid attribute to each logical drive at /sys/devices/<dev>/ccissX/cXdY/lunid for controller X, logical drive Y
---
.../ABI/testing/sysfs-bus-pci-devices-cciss | 7 +++++ drivers/block/cciss.c | 26 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 0 deletions(-)
Documentation/ABI/testing/sysfs-bus-pci-devices-cciss +7 -0
@@ -38,3 +38,10 @@ Kernel Version: 2.6.31 Contact: [email protected] Description: Kicks of a rescan of the controller to discover logical drive topology changes. + +Where: /sys/bus/pci/devices/<dev>/ccissX/cXdY/lunid +Date: August 2009 +Kernel Version: 2.6.31 +Contact: [email protected] +Description: Displays the 8-byte LUN ID used to address logical + drive Y of controller X.
drivers/block/cciss.c +26 -0
@@ -578,6 +578,31 @@ static ssize_t dev_show_rev(struct device *dev, }DEVICE_ATTR (rev,S_IRUGO , dev_show_rev,NULL ); +static ssize_t cciss_show_lunid (struct device *dev, +struct device_attribute *attr,char *buf) +{ +drive_info_struct *drv =dev_get_drvdata (dev); +struct ctlr_info *h =to_hba (drv->dev->parent); +unsigned long flags; +unsigned char lunid[8 ]; + +spin_lock_irqsave (CCISS_LOCK (h->ctlr), flags); +if (h->busy_configuring) { +spin_unlock_irqrestore (CCISS_LOCK (h->ctlr), flags); +return -EBUSY ; + } +if (!drv->heads) { +spin_unlock_irqrestore (CCISS_LOCK (h->ctlr), flags); +return -ENOTTY ; + } +memcpy (lunid, drv->LunID,sizeof (lunid)); +spin_unlock_irqrestore (CCISS_LOCK (h->ctlr), flags); +return snprintf (buf,20 ,"0x%02x%02x%02x%02x%02x%02x%02x%02x\n" , + 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 struct attribute *cciss_host_attrs[] = { &dev_attr_rescan.attr,NULL
@@ -603,6 +628,7 @@ static struct attribute *cciss_dev_attrs[] = { &dev_attr_model.attr, &dev_attr_vendor.attr, &dev_attr_rev.attr, + &dev_attr_lunid.attr, NULL };
PATCH 16/17 Add a "raid_level" attribute to each logical drive in /sys
In reply to Stephen M. CameronAdd raid_level attribute to each logical drive at /sys/devices/<dev>/ccissX/cXdY/raid_level for controller X, logical drive Y
---
.../ABI/testing/sysfs-bus-pci-devices-cciss | 7 ++++++ drivers/block/cciss.c | 24 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 0 deletions(-)
Documentation/ABI/testing/sysfs-bus-pci-devices-cciss +7 -0
@@ -45,3 +45,10 @@ Kernel Version: 2.6.31 Contact: [email protected] Description: Displays the 8-byte LUN ID used to address logical drive Y of controller X. + +Where: /sys/bus/pci/devices/<dev>/ccissX/cXdY/raid_level +Date: August 2009 +Kernel Version: 2.6.31 +Contact: [email protected] +Description: Displays the RAID level of logical drive Y of + controller X.
drivers/block/cciss.c +24 -0
@@ -603,6 +603,29 @@ static ssize_t cciss_show_lunid(struct device *dev, }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) +{ +drive_info_struct *drv =dev_get_drvdata (dev); +struct ctlr_info *h =to_hba (drv->dev->parent); +int raid; +unsigned long flags; + +spin_lock_irqsave (CCISS_LOCK (h->ctlr), flags); +if (h->busy_configuring) { +spin_unlock_irqrestore (CCISS_LOCK (h->ctlr), flags); +return -EBUSY ; + } + raid = drv->raid_level; +spin_unlock_irqrestore (CCISS_LOCK (h->ctlr), flags); +if (raid <0 || raid >5 ) + raid =RAID_UNKNOWN ; + +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 struct attribute *cciss_host_attrs[] = { &dev_attr_rescan.attr,NULL
@@ -629,6 +652,7 @@ static struct attribute *cciss_dev_attrs[] = { &dev_attr_vendor.attr, &dev_attr_rev.attr, &dev_attr_lunid.attr, + &dev_attr_raid_level.attr, NULL };
PATCH 17/17 Add usage_count attribute to each logical drive in /sys
In reply to Stephen M. CameronAdd usage_count attribute to each logical drive at /sys/devices/<dev>/ccissX/cXdY/usage_count for controller X, logical drive Y. The usage count is the number of times the device has currently been opened.
---
.../ABI/testing/sysfs-bus-pci-devices-cciss | 7 +++++++ drivers/block/cciss.c | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 0 deletions(-)
Documentation/ABI/testing/sysfs-bus-pci-devices-cciss +7 -0
@@ -52,3 +52,10 @@ Kernel Version: 2.6.31 Contact: [email protected] Description: Displays the RAID level of logical drive Y of controller X. + +Where: /sys/bus/pci/devices/<dev>/ccissX/cXdY/usage_count +Date: August 2009 +Kernel Version: 2.6.31 +Contact: [email protected] +Description: Displays the usage count (number of opens) of logical drive Y + of controller X.
drivers/block/cciss.c +20 -0
@@ -626,6 +626,25 @@ static ssize_t cciss_show_raid_level(struct device *dev, }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) +{ +drive_info_struct *drv =dev_get_drvdata (dev); +struct ctlr_info *h =to_hba (drv->dev->parent); +unsigned long flags; +int count; + +spin_lock_irqsave (CCISS_LOCK (h->ctlr), flags); +if (h->busy_configuring) { +spin_unlock_irqrestore (CCISS_LOCK (h->ctlr), flags); +return -EBUSY ; + } + count = drv->usage_count; +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 struct attribute *cciss_host_attrs[] = { &dev_attr_rescan.attr,NULL
@@ -653,6 +672,7 @@ static struct attribute *cciss_dev_attrs[] = { &dev_attr_rev.attr, &dev_attr_lunid.attr, &dev_attr_raid_level.attr, + &dev_attr_usage_count.attr, NULL };