[PATCH 2/3] cpqarray: ioctl support to configure LUNs dynamically

From: Saripalli, Venkata Ramanamurthy (STSD)
Date: Thu Aug 04 2005 - 00:03:02 EST


Patch 2 of 3
This patch adds support for IDAREGNEWDISK, IDADEREGDISK, IDAGETLOGINFO
ioctls required
to configure LUNs dynamically on SA4200 controller using ACU.

Please consider this for inclusion.

Signed-off-by: Ramanamurthy Saripalli <saripalli@xxxxxx>

cpqarray.c | 281
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
cpqarray.h | 1
ida_ioctl.h | 10 ++
3 files changed, 286 insertions(+), 6 deletions(-)
------------------------------------------------------------------------
------
diff -burpN old/drivers/block/cpqarray.c new2/drivers/block/cpqarray.c
--- old/drivers/block/cpqarray.c 2005-06-28 23:26:06.000000000
-0400
+++ new2/drivers/block/cpqarray.c 2005-06-28 23:42:22.000000000
-0400
@@ -45,13 +45,13 @@

#define SMART2_DRIVER_VERSION(maj,min,submin)
((maj<<16)|(min<<8)|(submin))

-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.6.0)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,6,0)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.6.1)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,6,1)

/* Embedded module documentation macros - see modules.h */
/* Original author Chris Frantz - Compaq Computer Corporation */
MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version
2.6.0");
+MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version
2.6.1");
MODULE_LICENSE("GPL");

#include "cpqarray.h"
@@ -143,6 +143,8 @@ static int pollcomplete(int ctlr);
static void getgeometry(int ctlr);
static void start_fwbk(int ctlr);

+static int register_new_disk(ctlr_info_t *h, int logovl);
+static int deregister_disk(struct gendisk *disk);
static cmdlist_t * cmd_alloc(ctlr_info_t *h, int get_from_pool);
static void cmd_free(ctlr_info_t *h, cmdlist_t *c, int got_from_pool);

@@ -157,6 +159,14 @@ static int sendcmd(
unsigned int blk,
unsigned int blkcnt,
unsigned int log_unit );
+static int sendcmd_withirq(
+ __u8 cmd,
+ int ctlr,
+ void *buff,
+ size_t size,
+ unsigned int blk,
+ unsigned int blkcnt,
+ unsigned int log_unit );

static int ida_open(struct inode *inode, struct file *filep);
static int ida_release(struct inode *inode, struct file *filep);
@@ -354,7 +364,10 @@ static void __devexit cpqarray_remove_on
kfree(hba[i]->cmd_pool_bits);
for(j = 0; j < NWD; j++) {
if (ida_gendisk[i][j]->flags & GENHD_FL_UP)
+ {
del_gendisk(ida_gendisk[i][j]);
+ }
+
devfs_remove("ida/c%dd%d",i,j);
put_disk(ida_gendisk[i][j]);
}
@@ -1141,8 +1154,11 @@ static int ida_ioctl(struct inode *inode
{
drv_info_t *drv = get_drv(inode->i_bdev->bd_disk);
ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);
+ struct gendisk *disk = inode->i_bdev->bd_disk;
int error;
int diskinfo[4];
+ int ctlr = MAJOR(inode->i_rdev) - COMPAQ_SMART2_MAJOR;
+ int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
struct hd_geometry __user *geo = (struct hd_geometry __user
*)arg;
ida_ioctl_t __user *io = (ida_ioctl_t __user *)arg;
ida_ioctl_t *my_io;
@@ -1212,15 +1228,268 @@ out_passthru:
return -EFAULT;
return(0);
}
+ case IDADEREGDISK:
+ return( deregister_disk(disk));
+ case IDAREGNEWDISK:
+ {
+ int logvol = arg;
+ return register_new_disk(host, logvol);
+ }

+ case IDAGETLOGINFO:
+ {
+ idaLogvolInfo_struct luninfo;
+
+ luninfo.LogVolID = dsk;
+ luninfo.num_opens = hba[ctlr]->drv[dsk].usage_count;
+
+ /* count partitions 1 to 15 with sizes > 0 */
+ /*start = (dsk << NWD_SHIFT);
+ for(i=1; i <IDA_MAX_PART; i++) {
+ int minor = start+i;
+ if(hba[ctlr]->sizes[minor] != 0)
+ num_parts++;
+ }
+ luninfo.num_parts = num_parts;*/
+ if (copy_to_user((void *) arg, &luninfo,
+ sizeof( idaLogvolInfo_struct) ))
+ return -EFAULT;
+ return(0);
+ }
default:
+ printk(KERN_WARNING "cpqarray: calling default
ioctl\n");
return -EINVAL;
}

}
-/*
- * ida_ctlr_ioctl is for passing commands to the controller from
userspace.
- * The command block (io) has already been copied to kernel space for
us,
+
+static int sendcmd_withirq(
+ __u8 cmd,
+ int ctlr,
+ void *buff,
+ size_t size,
+ unsigned int blk,
+ unsigned int blkcnt,
+ unsigned int log_unit )
+{
+ cmdlist_t *c;
+ unsigned long flags;
+ ctlr_info_t *info_p = hba[ctlr];
+ //DECLARE_COMPLETION(wait);
+
+
+ c = cmd_alloc(info_p, 0);
+ if(!c)
+ return IO_ERROR;
+
+ c->type = CMD_IOCTL_PEND;
+ c->ctlr = ctlr;
+ c->hdr.unit = log_unit;
+ c->hdr.prio = 0;
+ c->hdr.size = sizeof(rblk_t) >> 2;
+ c->size += sizeof(rblk_t);
+
+ /* The request information. */
+ c->req.hdr.next = 0;
+ c->req.hdr.rcode = 0;
+ c->req.bp = 0;
+ c->req.hdr.sg_cnt = 1;
+ c->req.hdr.reserved = 0;
+
+
+ if (size == 0)
+ c->req.sg[0].size = 512;
+ else
+ c->req.sg[0].size = size;
+
+ c->req.hdr.blk = blk;
+ c->req.hdr.blk_cnt = blkcnt;
+ c->req.hdr.cmd = (unsigned char) cmd;
+ c->req.sg[0].addr = (__u32) pci_map_single(info_p->pci_dev,
+ buff, c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);
+
+ /* Put the request on the tail of the request queue */
+ spin_lock_irqsave(IDA_LOCK(ctlr), flags);
+ addQ(&info_p->reqQ, c);
+ info_p->Qdepth++;
+ start_io(info_p);
+ spin_unlock_irqrestore(IDA_LOCK(ctlr), flags);
+
+ /* Wait for completion */
+ while(c->type != CMD_IOCTL_DONE)
+ schedule();
+
+ if (c->req.hdr.rcode & RCODE_FATAL) {
+ printk(KERN_WARNING "Fatal error on ida/c%dd%d\n",
+ c->ctlr, c->hdr.unit);
+ cmd_free(info_p, c, 0);
+ return(IO_ERROR);
+ }
+ if (c->req.hdr.rcode & RCODE_INVREQ) {
+ printk(KERN_WARNING "Invalid request on ida/c%dd%d =
(cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n",
c->ctlr, c->hdr.unit, c->req.hdr.cmd,
+ c->req.hdr.blk, c->req.hdr.blk_cnt,
+ c->req.hdr.sg_cnt, c->req.hdr.rcode);
+ cmd_free(info_p, c, 0);
+ return(IO_ERROR);
+ }
+ cmd_free(info_p, c, 0);
+ return(IO_OK);
+}
+
+static int register_new_disk(ctlr_info_t *h, int logvol)
+{
+ struct gendisk *disk;
+ int ctlr = h->ctlr;
+ int ret_code, size;
+ sense_log_drv_stat_t *id_lstatus_buf;
+ id_log_drv_t *id_ldrive;
+ drv_info_t *drv;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ if( (logvol < 0) || (logvol >= IDA_MAX_PART))
+ return -EINVAL;
+
+ /* disk is already registered */
+ if(hba[ctlr]->drv[logvol].nr_blks != 0 &&
+ hba[ctlr]->drv[logvol].cylinders != 0 &&
+ hba[ctlr]->drv[logvol].blk_size != 0 )
+ {
+ printk("disk already registered:%d\n", logvol);
+ return -EINVAL;
+ }
+
+ id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t),
GFP_KERNEL);
+ if(id_ldrive == NULL) {
+ printk( KERN_ERR "cpqarray: out of memory.\n");
+ return -1;
+ }
+ id_lstatus_buf = (sense_log_drv_stat_t
*)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
+ if(id_lstatus_buf == NULL) {
+ kfree(id_ldrive);
+ printk( KERN_ERR "cpqarray: out of memory.\n");
+ return -1;
+ }
+ size = sizeof(sense_log_drv_stat_t);
+
+ /*
+ Send "Identify logical drive status" cmd
+ */
+ ret_code = sendcmd_withirq(SENSE_LOG_DRV_STAT,
+ ctlr, id_lstatus_buf, size, 0, 0, logvol);
+ if (ret_code == IO_ERROR) {
+ /*
+ If can't get logical drive status, set
+ the logical drive map to 0, so the
+ idastubopen will fail for all logical drives
+ on the controller.
+ */
+ /* Free all the buffers and return */
+
+ kfree(id_lstatus_buf);
+ kfree(id_ldrive);
+ return -1;
+ }
+
+ /*
+ Make sure the logical drive is configured
+ */
+ if (id_lstatus_buf->status == LOG_NOT_CONF) {
+ printk(KERN_WARNING "cpqarray: c%dd%d array not
configured\n",
+ ctlr, logvol);
+ kfree(id_lstatus_buf);
+ kfree(id_ldrive);
+ return -1;
+ }
+
+ ret_code = sendcmd_withirq(ID_LOG_DRV, ctlr, id_ldrive,
+ sizeof(id_log_drv_t), 0, 0, logvol);
+ /*
+ If error, the bit for this
+ logical drive won't be set and
+ idastubopen will return error.
+ */
+ if (ret_code == IO_ERROR) {
+ printk(KERN_WARNING "cpqarray: c%dd%d unable to ID
logical volume\n",
+ ctlr,logvol);
+ kfree(id_lstatus_buf);
+ kfree(id_ldrive);
+ return -1;
+ }
+
+ drv = &h->drv[logvol];
+ drv->blk_size = id_ldrive->blk_size;
+ drv->nr_blks = id_ldrive->nr_blks;
+ drv->cylinders = id_ldrive->drv.cyl;
+ drv->heads = id_ldrive->drv.heads;
+ drv->sectors = id_ldrive->drv.sect_per_track;
+ h->log_drv_map |= (1 << logvol);
+
+ printk("cpqarray ida/c%dd%d: blksz=%d nr_blks=%d,
usage_cnt:%d\n",
+ ctlr, logvol, drv->blk_size, drv->nr_blks,
hba[ctlr]->drv[logvol].usage_count);
+
+ //hba[ctlr]->drv[logvol].usage_count = 0;
+ ++hba[ctlr]->log_drives;
+
+ /* setup partitions per disk */
+ disk = ida_gendisk[ctlr][logvol];
+
+ blk_queue_hardsect_size(hba[ctlr]->queue, drv->blk_size);
+ set_capacity(disk, h->drv[logvol].nr_blks);
+ disk->queue = hba[ctlr]->queue;
+ disk->private_data = drv;
+
+ /* if it's the controller it's already added */
+ if(logvol)
+ add_disk(disk);
+
+
+ kfree(id_lstatus_buf);
+ kfree(id_ldrive);
+
+ return (0);
+}
+
+
+static int deregister_disk(struct gendisk *disk)
+{
+ unsigned long flags;
+ ctlr_info_t *h = get_host(disk);
+ drv_info_t *drv = get_drv(disk);
+ int ctlr = h->ctlr;
+ int logvol = disk->first_minor >> NWD_SHIFT;
+
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ spin_lock_irqsave(IDA_LOCK(ctlr), flags);
+ /* make sure logical volume is NOT is use */
+ if( drv->usage_count > 1) {
+ spin_unlock_irqrestore(IDA_LOCK(ctlr), flags);
+ return -EBUSY;
+ }
+ spin_unlock_irqrestore(IDA_LOCK(ctlr), flags);
+
+ /* invalidate the devices and deregister the disk */
+ if (disk->flags & GENHD_FL_UP) {
+ printk("Before delete gendisk deregister ctlr:%d,
log:%d\n", ctlr,logvol);
+ del_gendisk(disk);
+ }
+
+ --h->log_drives;
+
+ /* zero out the disk size info */
+ drv->nr_blks = 0;
+ drv->cylinders = 0;
+ drv->blk_size = 0;
+ return(0);
+}
+
+

+
+/** The command block (io) has already been copied to kernel space for
us,
* however, any elements in the sglist need to be copied to kernel
space
* or copied back to userspace.
*
diff -burpN old/drivers/block/cpqarray.h new2/drivers/block/cpqarray.h
--- old/drivers/block/cpqarray.h 2005-06-28 23:26:14.000000000
-0400
+++ new2/drivers/block/cpqarray.h 2005-06-28 23:42:22.000000000
-0400
@@ -38,6 +38,7 @@
#define IO_ERROR 1
#define NWD 16
#define NWD_SHIFT 4
+#define IDA_MAX_PART 16

#define IDA_TIMER (5*HZ)
#define IDA_TIMEOUT (10*HZ)
diff -burpN old/drivers/block/ida_ioctl.h new2/drivers/block/ida_ioctl.h
--- old/drivers/block/ida_ioctl.h 2005-06-28 23:26:23.000000000
-0400
+++ new2/drivers/block/ida_ioctl.h 2005-06-28 23:42:22.000000000
-0400
@@ -31,6 +31,9 @@
#define IDAREVALIDATEVOLS 0x30303131
#define IDADRIVERVERSION 0x31313232
#define IDAGETPCIINFO 0x32323333
+#define IDADEREGDISK 0x33333434
+#define IDAREGNEWDISK 0x34343535
+#define IDAGETLOGINFO 0x35353636

typedef struct _ida_pci_info_struct
{
@@ -38,6 +41,13 @@ typedef struct _ida_pci_info_struct
unsigned char dev_fn;
__u32 board_id;
} ida_pci_info_struct;
+
+typedef struct _idaLogvolInfo_struct{
+ int LogVolID;
+ int num_opens; /* number of opens on the logical
volume */
+ int num_parts; /* number of partitions configured
on logvol */
+} idaLogvolInfo_struct;
+
/*
* Normally, the ioctl determines the logical unit for this command by
* the major,minor number of the fd passed to ioctl. If you need to
send
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/