Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9cef0d2f authored by Stephen M. Cameron's avatar Stephen M. Cameron Committed by Jens Axboe
Browse files

cciss: Dynamically allocate the drive_info_struct for each logical drive.



cciss: Dynamically allocate the drive_info_struct for each logical drive.
This reduces the size of the per-hba ctlr_info structure from 106936
bytes to 8132 bytes.  That's on 32-bit systems.  On 64-bit systems, the
improvement is even bigger.  Without this, the ctlr_info struct is so big
that the driver won't even load on a 64 bit system if CISS_MAX_LUN was
at it's current setting of 1024 logical drives.

Signed-off-by: default avatarStephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent e272afec
Loading
Loading
Loading
Loading
+165 −128
Original line number Original line Diff line number Diff line
@@ -201,6 +201,7 @@ static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c);
static void cciss_hba_release(struct device *dev);
static void cciss_hba_release(struct device *dev);
static void cciss_device_release(struct device *dev);
static void cciss_device_release(struct device *dev);
static void cciss_free_gendisk(ctlr_info_t *h, int drv_index);
static void cciss_free_gendisk(ctlr_info_t *h, int drv_index);
static void cciss_free_drive_info(ctlr_info_t *h, int drv_index);


#ifdef CONFIG_PROC_FS
#ifdef CONFIG_PROC_FS
static void cciss_procinit(int i);
static void cciss_procinit(int i);
@@ -327,7 +328,7 @@ static int cciss_seq_show(struct seq_file *seq, void *v)
	ctlr_info_t *h = seq->private;
	ctlr_info_t *h = seq->private;
	unsigned ctlr = h->ctlr;
	unsigned ctlr = h->ctlr;
	loff_t *pos = v;
	loff_t *pos = v;
	drive_info_struct *drv = &h->drv[*pos];
	drive_info_struct *drv = h->drv[*pos];


	if (*pos > h->highest_lun)
	if (*pos > h->highest_lun)
		return 0;
		return 0;
@@ -461,6 +462,7 @@ static void __devinit cciss_procinit(int i)
#define MAX_PRODUCT_NAME_LEN 19
#define MAX_PRODUCT_NAME_LEN 19


#define to_hba(n) container_of(n, struct ctlr_info, dev)
#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,
static ssize_t host_store_rescan(struct device *dev,
				 struct device_attribute *attr,
				 struct device_attribute *attr,
@@ -480,8 +482,8 @@ static ssize_t dev_show_unique_id(struct device *dev,
				 struct device_attribute *attr,
				 struct device_attribute *attr,
				 char *buf)
				 char *buf)
{
{
	drive_info_struct *drv = dev_get_drvdata(dev);
	drive_info_struct *drv = to_drv(dev);
	struct ctlr_info *h = to_hba(drv->dev->parent);
	struct ctlr_info *h = to_hba(drv->dev.parent);
	__u8 sn[16];
	__u8 sn[16];
	unsigned long flags;
	unsigned long flags;
	int ret = 0;
	int ret = 0;
@@ -510,8 +512,8 @@ static ssize_t dev_show_vendor(struct device *dev,
			       struct device_attribute *attr,
			       struct device_attribute *attr,
			       char *buf)
			       char *buf)
{
{
	drive_info_struct *drv = dev_get_drvdata(dev);
	drive_info_struct *drv = to_drv(dev);
	struct ctlr_info *h = to_hba(drv->dev->parent);
	struct ctlr_info *h = to_hba(drv->dev.parent);
	char vendor[VENDOR_LEN + 1];
	char vendor[VENDOR_LEN + 1];
	unsigned long flags;
	unsigned long flags;
	int ret = 0;
	int ret = 0;
@@ -534,8 +536,8 @@ static ssize_t dev_show_model(struct device *dev,
			      struct device_attribute *attr,
			      struct device_attribute *attr,
			      char *buf)
			      char *buf)
{
{
	drive_info_struct *drv = dev_get_drvdata(dev);
	drive_info_struct *drv = to_drv(dev);
	struct ctlr_info *h = to_hba(drv->dev->parent);
	struct ctlr_info *h = to_hba(drv->dev.parent);
	char model[MODEL_LEN + 1];
	char model[MODEL_LEN + 1];
	unsigned long flags;
	unsigned long flags;
	int ret = 0;
	int ret = 0;
@@ -558,8 +560,8 @@ static ssize_t dev_show_rev(struct device *dev,
			    struct device_attribute *attr,
			    struct device_attribute *attr,
			    char *buf)
			    char *buf)
{
{
	drive_info_struct *drv = dev_get_drvdata(dev);
	drive_info_struct *drv = to_drv(dev);
	struct ctlr_info *h = to_hba(drv->dev->parent);
	struct ctlr_info *h = to_hba(drv->dev.parent);
	char rev[REV_LEN + 1];
	char rev[REV_LEN + 1];
	unsigned long flags;
	unsigned long flags;
	int ret = 0;
	int ret = 0;
@@ -581,8 +583,8 @@ DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL);
static ssize_t cciss_show_lunid(struct device *dev,
static ssize_t cciss_show_lunid(struct device *dev,
				struct device_attribute *attr, char *buf)
				struct device_attribute *attr, char *buf)
{
{
	drive_info_struct *drv = dev_get_drvdata(dev);
	drive_info_struct *drv = to_drv(dev);
	struct ctlr_info *h = to_hba(drv->dev->parent);
	struct ctlr_info *h = to_hba(drv->dev.parent);
	unsigned long flags;
	unsigned long flags;
	unsigned char lunid[8];
	unsigned char lunid[8];


@@ -606,8 +608,8 @@ DEVICE_ATTR(lunid, S_IRUGO, cciss_show_lunid, NULL);
static ssize_t cciss_show_raid_level(struct device *dev,
static ssize_t cciss_show_raid_level(struct device *dev,
				     struct device_attribute *attr, char *buf)
				     struct device_attribute *attr, char *buf)
{
{
	drive_info_struct *drv = dev_get_drvdata(dev);
	drive_info_struct *drv = to_drv(dev);
	struct ctlr_info *h = to_hba(drv->dev->parent);
	struct ctlr_info *h = to_hba(drv->dev.parent);
	int raid;
	int raid;
	unsigned long flags;
	unsigned long flags;


@@ -629,8 +631,8 @@ DEVICE_ATTR(raid_level, S_IRUGO, cciss_show_raid_level, NULL);
static ssize_t cciss_show_usage_count(struct device *dev,
static ssize_t cciss_show_usage_count(struct device *dev,
				      struct device_attribute *attr, char *buf)
				      struct device_attribute *attr, char *buf)
{
{
	drive_info_struct *drv = dev_get_drvdata(dev);
	drive_info_struct *drv = to_drv(dev);
	struct ctlr_info *h = to_hba(drv->dev->parent);
	struct ctlr_info *h = to_hba(drv->dev.parent);
	unsigned long flags;
	unsigned long flags;
	int count;
	int count;


@@ -733,11 +735,12 @@ static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h)
}
}


/* cciss_device_release is called when the reference count
/* cciss_device_release is called when the reference count
 * of h->drv[x].dev goes to zero.
 * of h->drv[x]dev goes to zero.
 */
 */
static void cciss_device_release(struct device *dev)
static void cciss_device_release(struct device *dev)
{
{
	kfree(dev);
	drive_info_struct *drv = to_drv(dev);
	kfree(drv);
}
}


/*
/*
@@ -751,20 +754,16 @@ static long cciss_create_ld_sysfs_entry(struct ctlr_info *h,
{
{
	struct device *dev;
	struct device *dev;


	/* Special case for c*d0, we only create it once. */
	if (h->drv[drv_index]->device_initialized)
	if (drv_index == 0 && h->drv[drv_index].dev != NULL)
		return 0;
		return 0;


	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	dev = &h->drv[drv_index]->dev;
	if (!dev)
		return -ENOMEM;
	device_initialize(dev);
	device_initialize(dev);
	dev->type = &cciss_dev_type;
	dev->type = &cciss_dev_type;
	dev->bus = &cciss_bus_type;
	dev->bus = &cciss_bus_type;
	dev_set_name(dev, "c%dd%d", h->ctlr, drv_index);
	dev_set_name(dev, "c%dd%d", h->ctlr, drv_index);
	dev->parent = &h->dev;
	dev->parent = &h->dev;
	h->drv[drv_index].dev = dev;
	h->drv[drv_index]->device_initialized = 1;
	dev_set_drvdata(dev, &h->drv[drv_index]);
	return device_add(dev);
	return device_add(dev);
}
}


@@ -774,7 +773,7 @@ static long cciss_create_ld_sysfs_entry(struct ctlr_info *h,
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)
	int ctlr_exiting)
{
{
	struct device *dev = h->drv[drv_index].dev;
	struct device *dev = &h->drv[drv_index]->dev;


	/* special case for c*d0, we only destroy it on controller exit */
	/* special case for c*d0, we only destroy it on controller exit */
	if (drv_index == 0 && !ctlr_exiting)
	if (drv_index == 0 && !ctlr_exiting)
@@ -782,7 +781,7 @@ static void cciss_destroy_ld_sysfs_entry(struct ctlr_info *h, int drv_index,


	device_del(dev);
	device_del(dev);
	put_device(dev); /* the "final" put. */
	put_device(dev); /* the "final" put. */
	h->drv[drv_index].dev = NULL;
	h->drv[drv_index] = NULL;
}
}


/*
/*
@@ -1625,7 +1624,10 @@ static void cciss_check_queues(ctlr_info_t *h)
		/* make sure the disk has been added and the drive is real
		/* make sure the disk has been added and the drive is real
		 * because this can be called from the middle of init_one.
		 * because this can be called from the middle of init_one.
		 */
		 */
		if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
		if (!h->drv[curr_queue])
			continue;
		if (!(h->drv[curr_queue]->queue) ||
			!(h->drv[curr_queue]->heads))
			continue;
			continue;
		blk_start_queue(h->gendisk[curr_queue]->queue);
		blk_start_queue(h->gendisk[curr_queue]->queue);


@@ -1685,8 +1687,8 @@ static void cciss_softirq_done(struct request *rq)
static inline void log_unit_to_scsi3addr(ctlr_info_t *h,
static inline void log_unit_to_scsi3addr(ctlr_info_t *h,
	unsigned char scsi3addr[], uint32_t log_unit)
	unsigned char scsi3addr[], uint32_t log_unit)
{
{
	memcpy(scsi3addr, h->drv[log_unit].LunID,
	memcpy(scsi3addr, h->drv[log_unit]->LunID,
		sizeof(h->drv[log_unit].LunID));
		sizeof(h->drv[log_unit]->LunID));
}
}


/* This function gets the SCSI vendor, model, and revision of a logical drive
/* This function gets the SCSI vendor, model, and revision of a logical drive
@@ -1776,12 +1778,10 @@ static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
	disk->major = h->major;
	disk->major = h->major;
	disk->first_minor = drv_index << NWD_SHIFT;
	disk->first_minor = drv_index << NWD_SHIFT;
	disk->fops = &cciss_fops;
	disk->fops = &cciss_fops;
	if (h->drv[drv_index].dev == NULL) {
	if (cciss_create_ld_sysfs_entry(h, drv_index))
	if (cciss_create_ld_sysfs_entry(h, drv_index))
		goto cleanup_queue;
		goto cleanup_queue;
	}
	disk->private_data = h->drv[drv_index];
	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 */
	/* Set up queue information */
	blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask);
	blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask);
@@ -1799,13 +1799,13 @@ static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
	disk->queue->queuedata = h;
	disk->queue->queuedata = h;


	blk_queue_logical_block_size(disk->queue,
	blk_queue_logical_block_size(disk->queue,
				     h->drv[drv_index].block_size);
				     h->drv[drv_index]->block_size);


	/* Make sure all queue data is written out before */
	/* Make sure all queue data is written out before */
	/* setting h->drv[drv_index].queue, as setting this */
	/* setting h->drv[drv_index]->queue, as setting this */
	/* allows the interrupt handler to start the queue */
	/* allows the interrupt handler to start the queue */
	wmb();
	wmb();
	h->drv[drv_index].queue = disk->queue;
	h->drv[drv_index]->queue = disk->queue;
	add_disk(disk);
	add_disk(disk);
	return 0;
	return 0;


@@ -1840,7 +1840,7 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,


	/* Get information about the disk and modify the driver structure */
	/* Get information about the disk and modify the driver structure */
	inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
	inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
	drvinfo = kmalloc(sizeof(*drvinfo), GFP_KERNEL);
	drvinfo = kzalloc(sizeof(*drvinfo), GFP_KERNEL);
	if (inq_buff == NULL || drvinfo == NULL)
	if (inq_buff == NULL || drvinfo == NULL)
		goto mem_msg;
		goto mem_msg;


@@ -1876,16 +1876,19 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
				drvinfo->model, drvinfo->rev);
				drvinfo->model, drvinfo->rev);
	cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no,
	cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no,
			sizeof(drvinfo->serial_no));
			sizeof(drvinfo->serial_no));
	/* Save the lunid in case we deregister the disk, below. */
	memcpy(drvinfo->LunID, h->drv[drv_index]->LunID,
		sizeof(drvinfo->LunID));


	/* Is it the same disk we already know, and nothing's changed? */
	/* Is it the same disk we already know, and nothing's changed? */
	if (h->drv[drv_index].raid_level != -1 &&
	if (h->drv[drv_index]->raid_level != -1 &&
		((memcmp(drvinfo->serial_no,
		((memcmp(drvinfo->serial_no,
				h->drv[drv_index].serial_no, 16) == 0) &&
				h->drv[drv_index]->serial_no, 16) == 0) &&
		drvinfo->block_size == h->drv[drv_index].block_size &&
		drvinfo->block_size == h->drv[drv_index]->block_size &&
		drvinfo->nr_blocks == h->drv[drv_index].nr_blocks &&
		drvinfo->nr_blocks == h->drv[drv_index]->nr_blocks &&
		drvinfo->heads == h->drv[drv_index].heads &&
		drvinfo->heads == h->drv[drv_index]->heads &&
		drvinfo->sectors == h->drv[drv_index].sectors &&
		drvinfo->sectors == h->drv[drv_index]->sectors &&
		drvinfo->cylinders == h->drv[drv_index].cylinders))
		drvinfo->cylinders == h->drv[drv_index]->cylinders))
			/* The disk is unchanged, nothing to update */
			/* The disk is unchanged, nothing to update */
			goto freeret;
			goto freeret;


@@ -1895,18 +1898,17 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
	 * If the disk already exists then deregister it before proceeding
	 * If the disk already exists then deregister it before proceeding
	 * (unless it's the first disk (for the controller node).
	 * (unless it's the first disk (for the controller node).
	 */
	 */
	if (h->drv[drv_index].raid_level != -1 && drv_index != 0) {
	if (h->drv[drv_index]->raid_level != -1 && drv_index != 0) {
		printk(KERN_WARNING "disk %d has changed.\n", drv_index);
		printk(KERN_WARNING "disk %d has changed.\n", drv_index);
		spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
		spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
		h->drv[drv_index].busy_configuring = 1;
		h->drv[drv_index]->busy_configuring = 1;
		spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
		spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);


		/* deregister_disk sets h->drv[drv_index].queue = NULL
		/* deregister_disk sets h->drv[drv_index]->queue = NULL
		 * which keeps the interrupt handler from starting
		 * which keeps the interrupt handler from starting
		 * the queue.
		 * the queue.
		 */
		 */
		ret = deregister_disk(h, drv_index, 0, via_ioctl);
		ret = deregister_disk(h, drv_index, 0, via_ioctl);
		h->drv[drv_index].busy_configuring = 0;
	}
	}


	/* If the disk is in use return */
	/* If the disk is in use return */
@@ -1914,22 +1916,31 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
		goto freeret;
		goto freeret;


	/* Save the new information from cciss_geometry_inquiry
	/* Save the new information from cciss_geometry_inquiry
	 * and serial number inquiry.
	 * and serial number inquiry.  If the disk was deregistered
	 * above, then h->drv[drv_index] will be NULL.
	 */
	 */
	h->drv[drv_index].block_size = drvinfo->block_size;
	if (h->drv[drv_index] == NULL) {
	h->drv[drv_index].nr_blocks = drvinfo->nr_blocks;
		drvinfo->device_initialized = 0;
	h->drv[drv_index].heads = drvinfo->heads;
		h->drv[drv_index] = drvinfo;
	h->drv[drv_index].sectors = drvinfo->sectors;
		drvinfo = NULL; /* so it won't be freed below. */
	h->drv[drv_index].cylinders = drvinfo->cylinders;
	} else {
	h->drv[drv_index].raid_level = drvinfo->raid_level;
		/* special case for cxd0 */
	memcpy(h->drv[drv_index].serial_no, drvinfo->serial_no, 16);
		h->drv[drv_index]->block_size = drvinfo->block_size;
	memcpy(h->drv[drv_index].vendor, drvinfo->vendor, VENDOR_LEN + 1);
		h->drv[drv_index]->nr_blocks = drvinfo->nr_blocks;
	memcpy(h->drv[drv_index].model, drvinfo->model, MODEL_LEN + 1);
		h->drv[drv_index]->heads = drvinfo->heads;
	memcpy(h->drv[drv_index].rev, drvinfo->rev, REV_LEN + 1);
		h->drv[drv_index]->sectors = drvinfo->sectors;
		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;
	++h->num_luns;
	disk = h->gendisk[drv_index];
	disk = h->gendisk[drv_index];
	set_capacity(disk, h->drv[drv_index].nr_blocks);
	set_capacity(disk, h->drv[drv_index]->nr_blocks);


	/* If it's not disk 0 (drv_index != 0)
	/* If it's not disk 0 (drv_index != 0)
	 * or if it was disk 0, but there was previously
	 * or if it was disk 0, but there was previously
@@ -1940,6 +1951,7 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
	if (drv_index || first_time) {
	if (drv_index || first_time) {
		if (cciss_add_disk(h, disk, drv_index) != 0) {
		if (cciss_add_disk(h, disk, drv_index) != 0) {
			cciss_free_gendisk(h, drv_index);
			cciss_free_gendisk(h, drv_index);
			cciss_free_drive_info(h, drv_index);
			printk(KERN_WARNING "cciss:%d could not update "
			printk(KERN_WARNING "cciss:%d could not update "
				"disk %d\n", h->ctlr, drv_index);
				"disk %d\n", h->ctlr, drv_index);
			--h->num_luns;
			--h->num_luns;
@@ -1956,28 +1968,64 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
}
}


/* This function will find the first index of the controllers drive array
/* This function will find the first index of the controllers drive array
 * that has a -1 for the raid_level and will return that index.  This is
 * that has a null drv pointer and allocate the drive info struct and
 * where new drives will be added.  If the index to be returned is greater
 * will return that index   This is where new drives will be added.
 * than the highest_lun index for the controller then highest_lun is set
 * If the index to be returned is greater than the highest_lun index for
 * to this new index.  If there are no available indexes then -1 is returned.
 * the controller then highest_lun is set * to this new index.
 * "controller_node" is used to know if this is a real logical drive, or just
 * If there are no available indexes or if tha allocation fails, then -1
 * the controller node, which determines if this counts towards highest_lun.
 * is returned.  * "controller_node" is used to know if this is a real
 * logical drive, or just the controller node, which determines if this
 * counts towards highest_lun.
 */
 */
static int cciss_find_free_drive_index(int ctlr, int controller_node)
static int cciss_alloc_drive_info(ctlr_info_t *h, int controller_node)
{
{
	int i;
	int i;
	drive_info_struct *drv;


	/* Search for an empty slot for our drive info */
	for (i = 0; i < CISS_MAX_LUN; i++) {
	for (i = 0; i < CISS_MAX_LUN; i++) {
		if (hba[ctlr]->drv[i].raid_level == -1) {

			if (i > hba[ctlr]->highest_lun)
		/* if not cxd0 case, and it's occupied, skip it. */
				if (!controller_node)
		if (h->drv[i] && i != 0)
					hba[ctlr]->highest_lun = i;
			continue;
		/*
		 * If it's cxd0 case, and drv is alloc'ed already, and a
		 * disk is configured there, skip it.
		 */
		if (i == 0 && h->drv[i] && h->drv[i]->raid_level != -1)
			continue;

		/*
		 * We've found an empty slot.  Update highest_lun
		 * provided this isn't just the fake cxd0 controller node.
		 */
		if (i > h->highest_lun && !controller_node)
			h->highest_lun = i;

		/* If adding a real disk at cxd0, and it's already alloc'ed */
		if (i == 0 && h->drv[i] != NULL)
			return i;

		/*
		 * Found an empty slot, not already alloc'ed.  Allocate it.
		 * Mark it with raid_level == -1, so we know it's new later on.
		 */
		drv = kzalloc(sizeof(*drv), GFP_KERNEL);
		if (!drv)
			return -1;
		drv->raid_level = -1; /* so we know it's new */
		h->drv[i] = drv;
		return i;
		return i;
		}
	}
	}
	return -1;
	return -1;
}
}


static void cciss_free_drive_info(ctlr_info_t *h, int drv_index)
{
	kfree(h->drv[drv_index]);
	h->drv[drv_index] = NULL;
}

static void cciss_free_gendisk(ctlr_info_t *h, int drv_index)
static void cciss_free_gendisk(ctlr_info_t *h, int drv_index)
{
{
	put_disk(h->gendisk[drv_index]);
	put_disk(h->gendisk[drv_index]);
@@ -1998,7 +2046,7 @@ static int cciss_add_gendisk(ctlr_info_t *h, unsigned char lunid[],
{
{
	int drv_index;
	int drv_index;


	drv_index = cciss_find_free_drive_index(h->ctlr, controller_node);
	drv_index = cciss_alloc_drive_info(h, controller_node);
	if (drv_index == -1)
	if (drv_index == -1)
		return -1;
		return -1;


@@ -2010,24 +2058,24 @@ static int cciss_add_gendisk(ctlr_info_t *h, unsigned char lunid[],
			printk(KERN_ERR "cciss%d: could not "
			printk(KERN_ERR "cciss%d: could not "
				"allocate a new disk %d\n",
				"allocate a new disk %d\n",
				h->ctlr, drv_index);
				h->ctlr, drv_index);
			return -1;
			goto err_free_drive_info;
		}
		}
	}
	}
	memcpy(h->drv[drv_index].LunID, lunid,
	memcpy(h->drv[drv_index]->LunID, lunid,
		sizeof(h->drv[drv_index].LunID));
		sizeof(h->drv[drv_index]->LunID));
	if (h->drv[drv_index].dev == NULL) {
	if (cciss_create_ld_sysfs_entry(h, drv_index))
	if (cciss_create_ld_sysfs_entry(h, drv_index))
		goto err_free_disk;
		goto err_free_disk;
	}
	/* Don't need to mark this busy because nobody */
	/* Don't need to mark this busy because nobody */
	/* else knows about this disk yet to contend */
	/* else knows about this disk yet to contend */
	/* for access to it. */
	/* for access to it. */
	h->drv[drv_index].busy_configuring = 0;
	h->drv[drv_index]->busy_configuring = 0;
	wmb();
	wmb();
	return drv_index;
	return drv_index;


err_free_disk:
err_free_disk:
	cciss_free_gendisk(h, drv_index);
	cciss_free_gendisk(h, drv_index);
err_free_drive_info:
	cciss_free_drive_info(h, drv_index);
	return -1;
	return -1;
}
}


@@ -2047,17 +2095,18 @@ static void cciss_add_controller_node(ctlr_info_t *h)
	drv_index = cciss_add_gendisk(h, CTLR_LUNID, 1);
	drv_index = cciss_add_gendisk(h, CTLR_LUNID, 1);
	if (drv_index == -1)
	if (drv_index == -1)
		goto error;
		goto error;
	h->drv[drv_index].block_size = 512;
	h->drv[drv_index]->block_size = 512;
	h->drv[drv_index].nr_blocks = 0;
	h->drv[drv_index]->nr_blocks = 0;
	h->drv[drv_index].heads = 0;
	h->drv[drv_index]->heads = 0;
	h->drv[drv_index].sectors = 0;
	h->drv[drv_index]->sectors = 0;
	h->drv[drv_index].cylinders = 0;
	h->drv[drv_index]->cylinders = 0;
	h->drv[drv_index].raid_level = -1;
	h->drv[drv_index]->raid_level = -1;
	memset(h->drv[drv_index].serial_no, 0, 16);
	memset(h->drv[drv_index]->serial_no, 0, 16);
	disk = h->gendisk[drv_index];
	disk = h->gendisk[drv_index];
	if (cciss_add_disk(h, disk, drv_index) == 0)
	if (cciss_add_disk(h, disk, drv_index) == 0)
		return;
		return;
	cciss_free_gendisk(h, drv_index);
	cciss_free_gendisk(h, drv_index);
	cciss_free_drive_info(h, drv_index);
error:
error:
	printk(KERN_WARNING "cciss%d: could not "
	printk(KERN_WARNING "cciss%d: could not "
		"add disk 0.\n", h->ctlr);
		"add disk 0.\n", h->ctlr);
@@ -2136,12 +2185,12 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time,
		drv_found = 0;
		drv_found = 0;


		/* skip holes in the array from already deleted drives */
		/* skip holes in the array from already deleted drives */
		if (h->drv[i].raid_level == -1)
		if (h->drv[i] == NULL)
			continue;
			continue;


		for (j = 0; j < num_luns; j++) {
		for (j = 0; j < num_luns; j++) {
			memcpy(lunid, &ld_buff->LUN[j][0], sizeof(lunid));
			memcpy(lunid, &ld_buff->LUN[j][0], sizeof(lunid));
			if (memcmp(h->drv[i].LunID, lunid,
			if (memcmp(h->drv[i]->LunID, lunid,
				sizeof(lunid)) == 0) {
				sizeof(lunid)) == 0) {
				drv_found = 1;
				drv_found = 1;
				break;
				break;
@@ -2150,10 +2199,11 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time,
		if (!drv_found) {
		if (!drv_found) {
			/* Deregister it from the OS, it's gone. */
			/* Deregister it from the OS, it's gone. */
			spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
			spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
			h->drv[i].busy_configuring = 1;
			h->drv[i]->busy_configuring = 1;
			spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
			spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
			return_code = deregister_disk(h, i, 1, via_ioctl);
			return_code = deregister_disk(h, i, 1, via_ioctl);
			h->drv[i].busy_configuring = 0;
			if (h->drv[i] != NULL)
				h->drv[i]->busy_configuring = 0;
		}
		}
	}
	}


@@ -2174,9 +2224,9 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time,
		 * the first free index and add it.
		 * the first free index and add it.
		 */
		 */
		for (j = 0; j <= h->highest_lun; j++) {
		for (j = 0; j <= h->highest_lun; j++) {
			if (h->drv[j].raid_level != -1 &&
			if (h->drv[j] != NULL &&
				memcmp(h->drv[j].LunID, lunid,
				memcmp(h->drv[j]->LunID, lunid,
					sizeof(h->drv[j].LunID)) == 0) {
					sizeof(h->drv[j]->LunID)) == 0) {
				drv_index = j;
				drv_index = j;
				drv_found = 1;
				drv_found = 1;
				break;
				break;
@@ -2253,11 +2303,12 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,
	int i;
	int i;
	struct gendisk *disk;
	struct gendisk *disk;
	drive_info_struct *drv;
	drive_info_struct *drv;
	int recalculate_highest_lun;


	if (!capable(CAP_SYS_RAWIO))
	if (!capable(CAP_SYS_RAWIO))
		return -EPERM;
		return -EPERM;


	drv = &h->drv[drv_index];
	drv = h->drv[drv_index];
	disk = h->gendisk[drv_index];
	disk = h->gendisk[drv_index];


	/* make sure logical volume is NOT is use */
	/* make sure logical volume is NOT is use */
@@ -2267,6 +2318,8 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,
	} else if (drv->usage_count > 0)
	} else if (drv->usage_count > 0)
		return -EBUSY;
		return -EBUSY;


	recalculate_highest_lun = (drv == h->drv[h->highest_lun]);

	/* invalidate the devices and deregister the disk.  If it is disk
	/* invalidate the devices and deregister the disk.  If it is disk
	 * zero do not deregister it but just zero out it's values.  This
	 * zero do not deregister it but just zero out it's values.  This
	 * allows us to delete disk zero but keep the controller registered.
	 * allows us to delete disk zero but keep the controller registered.
@@ -2277,14 +2330,8 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,
			cciss_destroy_ld_sysfs_entry(h, drv_index, 0);
			cciss_destroy_ld_sysfs_entry(h, drv_index, 0);
			del_gendisk(disk);
			del_gendisk(disk);
		}
		}
		if (q) {
		if (q)
			blk_cleanup_queue(q);
			blk_cleanup_queue(q);
			/* Set drv->queue to NULL so that we do not try
			 * to call blk_start_queue on this queue in the
			 * interrupt handler
			 */
			drv->queue = NULL;
		}
		/* If clear_all is set then we are deleting the logical
		/* If clear_all is set then we are deleting the logical
		 * drive, not just refreshing its info.  For drives
		 * drive, not just refreshing its info.  For drives
		 * other than disk 0 we will call put_disk.  We do not
		 * other than disk 0 we will call put_disk.  We do not
@@ -2307,25 +2354,21 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,
		}
		}
	} else {
	} else {
		set_capacity(disk, 0);
		set_capacity(disk, 0);
		cciss_clear_drive_info(drv);
	}
	}


	--h->num_luns;
	--h->num_luns;
	cciss_clear_drive_info(drv);


	if (clear_all) {
	/* if it was the last disk, find the new hightest lun */
		/* check to see if it was the last disk */
	if (clear_all && recalculate_highest_lun) {
		if (drv == h->drv + h->highest_lun) {
			/* if so, find the new hightest lun */
		int i, newhighest = -1;
		int i, newhighest = -1;
		for (i = 0; i <= h->highest_lun; i++) {
		for (i = 0; i <= h->highest_lun; i++) {
			/* if the disk has size > 0, it is available */
			/* if the disk has size > 0, it is available */
				if (h->drv[i].heads)
			if (h->drv[i] && h->drv[i]->heads)
				newhighest = i;
				newhighest = i;
		}
		}
		h->highest_lun = newhighest;
		h->highest_lun = newhighest;
	}
	}
		memset(drv->LunID, 0, sizeof(drv->LunID));
	}
	return 0;
	return 0;
}
}


@@ -2755,7 +2798,7 @@ static int cciss_revalidate(struct gendisk *disk)
	InquiryData_struct *inq_buff = NULL;
	InquiryData_struct *inq_buff = NULL;


	for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
	for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
		if (memcmp(h->drv[logvol].LunID, drv->LunID,
		if (memcmp(h->drv[logvol]->LunID, drv->LunID,
			sizeof(drv->LunID)) == 0) {
			sizeof(drv->LunID)) == 0) {
			FOUND = 1;
			FOUND = 1;
			break;
			break;
@@ -4293,8 +4336,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
	hba[i]->num_luns = 0;
	hba[i]->num_luns = 0;
	hba[i]->highest_lun = -1;
	hba[i]->highest_lun = -1;
	for (j = 0; j < CISS_MAX_LUN; j++) {
	for (j = 0; j < CISS_MAX_LUN; j++) {
		hba[i]->drv[j].raid_level = -1;
		hba[i]->drv[j] = NULL;
		hba[i]->drv[j].queue = NULL;
		hba[i]->gendisk[j] = NULL;
		hba[i]->gendisk[j] = NULL;
	}
	}


@@ -4349,12 +4391,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
	cciss_destroy_hba_sysfs_entry(hba[i]);
	cciss_destroy_hba_sysfs_entry(hba[i]);
clean0:
clean0:
	hba[i]->busy_initializing = 0;
	hba[i]->busy_initializing = 0;
	/* cleanup any queues that may have been initialized */

	for (j=0; j <= hba[i]->highest_lun; j++){
		drive_info_struct *drv = &(hba[i]->drv[j]);
		if (drv->queue)
			blk_cleanup_queue(drv->queue);
	}
	/*
	/*
	 * Deliberately omit pci_disable_device(): it does something nasty to
	 * Deliberately omit pci_disable_device(): it does something nasty to
	 * Smart Array controllers that pci_enable_device does not undo
	 * Smart Array controllers that pci_enable_device does not undo
+3 −2
Original line number Original line Diff line number Diff line
@@ -45,13 +45,14 @@ typedef struct _drive_info_struct
				   * to prevent it from being opened or it's
				   * to prevent it from being opened or it's
				   * queue from being started.
				   * queue from being started.
				   */
				   */
	struct	device *dev;
	struct	device dev;
	__u8 serial_no[16]; /* from inquiry page 0x83,
	__u8 serial_no[16]; /* from inquiry page 0x83,
			     * not necc. null terminated.
			     * not necc. null terminated.
			     */
			     */
	char vendor[VENDOR_LEN + 1]; /* SCSI vendor string */
	char vendor[VENDOR_LEN + 1]; /* SCSI vendor string */
	char model[MODEL_LEN + 1];   /* SCSI model string */
	char model[MODEL_LEN + 1];   /* SCSI model string */
	char rev[REV_LEN + 1];       /* SCSI revision string */
	char rev[REV_LEN + 1];       /* SCSI revision string */
	char device_initialized;     /* indicates whether dev is initialized */
} drive_info_struct;
} drive_info_struct;


struct ctlr_info 
struct ctlr_info 
@@ -87,7 +88,7 @@ struct ctlr_info
	BYTE	cciss_read_capacity;
	BYTE	cciss_read_capacity;


	// information about each logical volume
	// information about each logical volume
	drive_info_struct drv[CISS_MAX_LUN];
	drive_info_struct *drv[CISS_MAX_LUN];


	struct access_method access;
	struct access_method access;