#include <linux/init.h>
#include <linux/hdreg.h>
#include <linux/spinlock.h>
+#include <linux/compat.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/completion.h>
#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq CISS Driver (v 2.6.2)"
+#define DRIVER_NAME "HP CISS Driver (v 2.6.2)"
#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,2)
/* Embedded module documentation macros - see modules.h */
MODULE_AUTHOR("Hewlett-Packard Company");
MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.2");
MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
- " SA6i");
+ " SA6i V100");
MODULE_LICENSE("GPL");
#include "cciss_cmd.h"
0x0E11, 0x4091, 0, 0, 0},
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
0x0E11, 0x409E, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISS,
0x103C, 0x3211, 0, 0, 0},
{0,}
};
/*define how many times we will try a command because of bus resets */
#define MAX_CMD_RETRIES 3
-#define READ_AHEAD 256
+#define READ_AHEAD 1024
#define NR_CMDS 384 /* #commands that can be outstanding */
#define MAX_CTLR 8
static void cciss_getgeometry(int cntl_num);
-static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c);
static void start_io( ctlr_info_t *h);
static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size,
unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
.revalidate_disk= cciss_revalidate,
};
+/*
+ * Enqueuing and dequeuing functions for cmdlists.
+ */
+static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c)
+{
+ if (*Qptr == NULL) {
+ *Qptr = c;
+ c->next = c->prev = c;
+ } else {
+ c->prev = (*Qptr)->prev;
+ c->next = (*Qptr);
+ (*Qptr)->prev->next = c;
+ (*Qptr)->prev = c;
+ }
+}
+
+static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
+ CommandList_struct *c)
+{
+ if (c && c->next != c) {
+ if (*Qptr == c) *Qptr = c->next;
+ c->prev->next = c->next;
+ c->next->prev = c->prev;
+ } else {
+ *Qptr = NULL;
+ }
+ return c;
+}
+#ifdef CONFIG_PROC_FS
+
#include "cciss_scsi.c" /* For SCSI tape support */
/*
* Report information about this controller.
*/
-#define ENG_GIG 1048576000
+#define ENG_GIG 1000000000
#define ENG_GIG_FACTOR (ENG_GIG/512)
#define RAID_UNKNOWN 6
-static const char *raid_label[] = {"0","4","1(0+1)","5","5+1","ADG",
+static const char *raid_label[] = {"0","4","1(1+0)","5","5+1","ADG",
"UNKNOWN"};
-#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_cciss;
ctlr_info_t *h = (ctlr_info_t*)data;
drive_info_struct *drv;
unsigned long flags;
- unsigned int vol_sz, vol_sz_frac;
+ sector_t vol_sz, vol_sz_frac;
ctlr = h->ctlr;
pos += size; len += size;
cciss_proc_tape_report(ctlr, buffer, &pos, &len);
for(i=0; i<=h->highest_lun; i++) {
- sector_t tmp;
drv = &h->drv[i];
if (drv->block_size == 0)
continue;
- vol_sz = drv->nr_blocks;
- sector_div(vol_sz, ENG_GIG_FACTOR);
-
- /*
- * Awkwardly do this:
- * vol_sz_frac =
- * (drv->nr_blocks%ENG_GIG_FACTOR)*100/ENG_GIG_FACTOR;
- */
- tmp = drv->nr_blocks;
- vol_sz_frac = sector_div(tmp, ENG_GIG_FACTOR);
-
- /* Now, vol_sz_frac = (drv->nr_blocks%ENG_GIG_FACTOR) */
+ 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);
if (drv->raid_level > 5)
drv->raid_level = RAID_UNKNOWN;
size = sprintf(buffer+len, "cciss/c%dd%d:"
- "\t%4d.%02dGB\tRAID %s\n",
- ctlr, i, vol_sz,vol_sz_frac,
+ "\t%4u.%02uGB\tRAID %s\n",
+ ctlr, i, (int)vol_sz, (int)vol_sz_frac,
raid_label[drv->raid_level]);
pos += size; len += size;
}
}
static int
-cciss_proc_write(struct file *file, const char *buffer,
+cciss_proc_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
unsigned char cmd[80];
return 0;
}
+#ifdef CONFIG_COMPAT
+/* for AMD 64 bit kernel compatibility with 32-bit userland ioctls */
+extern long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+extern int
+register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int,
+ unsigned int, unsigned long, struct file *));
+extern int unregister_ioctl32_conversion(unsigned int cmd);
+
+static int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg, struct file *file);
+static int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
+ struct file *file);
+
+typedef int (*handler_type) (unsigned int, unsigned int, unsigned long, struct file *);
+
+static struct ioctl32_map {
+ unsigned int cmd;
+ handler_type handler;
+ int registered;
+} cciss_ioctl32_map[] = {
+ { CCISS_GETPCIINFO, (handler_type) sys_ioctl, 0 },
+ { CCISS_GETINTINFO, (handler_type) sys_ioctl, 0 },
+ { CCISS_SETINTINFO, (handler_type) sys_ioctl, 0 },
+ { CCISS_GETNODENAME, (handler_type) sys_ioctl, 0 },
+ { CCISS_SETNODENAME, (handler_type) sys_ioctl, 0 },
+ { CCISS_GETHEARTBEAT, (handler_type) sys_ioctl, 0 },
+ { CCISS_GETBUSTYPES, (handler_type) sys_ioctl, 0 },
+ { CCISS_GETFIRMVER, (handler_type) sys_ioctl, 0 },
+ { CCISS_GETDRIVVER, (handler_type) sys_ioctl, 0 },
+ { CCISS_REVALIDVOLS, (handler_type) sys_ioctl, 0 },
+ { CCISS_PASSTHRU32, cciss_ioctl32_passthru, 0 },
+ { CCISS_DEREGDISK, (handler_type) sys_ioctl, 0 },
+ { CCISS_REGNEWDISK, (handler_type) sys_ioctl, 0 },
+ { CCISS_REGNEWD, (handler_type) sys_ioctl, 0 },
+ { CCISS_RESCANDISK, (handler_type) sys_ioctl, 0 },
+ { CCISS_GETLUNINFO, (handler_type) sys_ioctl, 0 },
+ { CCISS_BIG_PASSTHRU32, cciss_ioctl32_big_passthru, 0 },
+};
+#define NCCISS_IOCTL32_ENTRIES (sizeof(cciss_ioctl32_map) / sizeof(cciss_ioctl32_map[0]))
+static void register_cciss_ioctl32(void)
+{
+ int i, rc;
+
+ for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) {
+ rc = register_ioctl32_conversion(
+ cciss_ioctl32_map[i].cmd,
+ cciss_ioctl32_map[i].handler);
+ if (rc != 0) {
+ printk(KERN_WARNING "cciss: failed to register "
+ "32 bit compatible ioctl 0x%08x\n",
+ cciss_ioctl32_map[i].cmd);
+ cciss_ioctl32_map[i].registered = 0;
+ } else
+ cciss_ioctl32_map[i].registered = 1;
+ }
+}
+static void unregister_cciss_ioctl32(void)
+{
+ int i, rc;
+
+ for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) {
+ if (!cciss_ioctl32_map[i].registered)
+ continue;
+ rc = unregister_ioctl32_conversion(
+ cciss_ioctl32_map[i].cmd);
+ if (rc == 0) {
+ cciss_ioctl32_map[i].registered = 0;
+ continue;
+ }
+ printk(KERN_WARNING "cciss: failed to unregister "
+ "32 bit compatible ioctl 0x%08x\n",
+ cciss_ioctl32_map[i].cmd);
+ }
+}
+int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
+ struct file *file)
+{
+ IOCTL32_Command_struct __user *arg32 =
+ (IOCTL32_Command_struct __user *) arg;
+ IOCTL_Command_struct arg64;
+ IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
+ int err;
+ u32 cp;
+
+ err = 0;
+ err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
+ err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
+ err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+ err |= get_user(arg64.buf_size, &arg32->buf_size);
+ err |= get_user(cp, &arg32->buf);
+ arg64.buf = compat_ptr(cp);
+ err |= copy_to_user(p, &arg64, sizeof(arg64));
+
+ if (err)
+ return -EFAULT;
+
+ err = sys_ioctl(fd, CCISS_PASSTHRU, (unsigned long) p);
+ if (err)
+ return err;
+ err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
+ if (err)
+ return -EFAULT;
+ return err;
+}
+
+int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
+ struct file *file)
+{
+ BIG_IOCTL32_Command_struct __user *arg32 =
+ (BIG_IOCTL32_Command_struct __user *) arg;
+ BIG_IOCTL_Command_struct arg64;
+ BIG_IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
+ int err;
+ u32 cp;
+
+ err = 0;
+ err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
+ err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
+ err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+ err |= get_user(arg64.buf_size, &arg32->buf_size);
+ err |= get_user(arg64.malloc_size, &arg32->malloc_size);
+ err |= get_user(cp, &arg32->buf);
+ arg64.buf = compat_ptr(cp);
+ err |= copy_to_user(p, &arg64, sizeof(arg64));
+
+ if (err)
+ return -EFAULT;
+
+ err = sys_ioctl(fd, CCISS_BIG_PASSTHRU, (unsigned long) p);
+ if (err)
+ return err;
+ err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
+ if (err)
+ return -EFAULT;
+ return err;
+}
+#else
+static inline void register_cciss_ioctl32(void) {}
+static inline void unregister_cciss_ioctl32(void) {}
+#endif
/*
* ioctl
*/
ctlr_info_t *host = get_host(disk);
drive_info_struct *drv = get_drv(disk);
int ctlr = host->ctlr;
+ void __user *argp = (void __user *)arg;
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg);
} else
return -ENXIO;
driver_geo.start= get_start_sect(inode->i_bdev);
- if (copy_to_user((void *) arg, &driver_geo,
- sizeof( struct hd_geometry)))
+ if (copy_to_user(argp, &driver_geo, sizeof(struct hd_geometry)))
return -EFAULT;
return(0);
}
pciinfo.bus = host->pdev->bus->number;
pciinfo.dev_fn = host->pdev->devfn;
pciinfo.board_id = host->board_id;
- if (copy_to_user((void *) arg, &pciinfo, sizeof( cciss_pci_info_struct )))
+ if (copy_to_user(argp, &pciinfo, sizeof( cciss_pci_info_struct )))
return -EFAULT;
return(0);
}
if (!arg) return -EINVAL;
intinfo.delay = readl(&host->cfgtable->HostWrite.CoalIntDelay);
intinfo.count = readl(&host->cfgtable->HostWrite.CoalIntCount);
- if (copy_to_user((void *) arg, &intinfo, sizeof( cciss_coalint_struct )))
+ if (copy_to_user(argp, &intinfo, sizeof( cciss_coalint_struct )))
return -EFAULT;
return(0);
}
if (!arg) return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) return -EPERM;
- if (copy_from_user(&intinfo, (void *) arg, sizeof( cciss_coalint_struct)))
+ if (copy_from_user(&intinfo, argp, sizeof( cciss_coalint_struct)))
return -EFAULT;
if ( (intinfo.delay == 0 ) && (intinfo.count == 0))
if (!arg) return -EINVAL;
for(i=0;i<16;i++)
NodeName[i] = readb(&host->cfgtable->ServerName[i]);
- if (copy_to_user((void *) arg, NodeName, sizeof( NodeName_type)))
+ if (copy_to_user(argp, NodeName, sizeof( NodeName_type)))
return -EFAULT;
return(0);
}
if (!arg) return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) return -EPERM;
- if (copy_from_user(NodeName, (void *) arg, sizeof( NodeName_type)))
+ if (copy_from_user(NodeName, argp, sizeof( NodeName_type)))
return -EFAULT;
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
if (!arg) return -EINVAL;
heartbeat = readl(&host->cfgtable->HeartBeat);
- if (copy_to_user((void *) arg, &heartbeat, sizeof( Heartbeat_type)))
+ if (copy_to_user(argp, &heartbeat, sizeof( Heartbeat_type)))
return -EFAULT;
return(0);
}
if (!arg) return -EINVAL;
BusTypes = readl(&host->cfgtable->BusTypes);
- if (copy_to_user((void *) arg, &BusTypes, sizeof( BusTypes_type) ))
+ if (copy_to_user(argp, &BusTypes, sizeof( BusTypes_type) ))
return -EFAULT;
return(0);
}
if (!arg) return -EINVAL;
memcpy(firmware, host->firm_ver, 4);
- if (copy_to_user((void *) arg, firmware, sizeof( FirmwareVer_type)))
+ if (copy_to_user(argp, firmware, sizeof( FirmwareVer_type)))
return -EFAULT;
return(0);
}
if (!arg) return -EINVAL;
- if (copy_to_user((void *) arg, &DriverVer, sizeof( DriverVer_type) ))
+ if (copy_to_user(argp, &DriverVer, sizeof( DriverVer_type) ))
return -EFAULT;
return(0);
}
if (disk->part[i]->nr_sects != 0)
luninfo.num_parts++;
}
- if (copy_to_user((void *) arg, &luninfo,
+ if (copy_to_user(argp, &luninfo,
sizeof(LogvolInfo_struct)))
return -EFAULT;
return(0);
if (!capable(CAP_SYS_RAWIO)) return -EPERM;
- if (copy_from_user(&iocommand, (void *) arg, sizeof( IOCTL_Command_struct) ))
+ if (copy_from_user(&iocommand, argp, sizeof( IOCTL_Command_struct) ))
return -EFAULT;
if((iocommand.buf_size < 1) &&
(iocommand.Request.Type.Direction != XFER_NONE))
kfree(buff);
return -EFAULT;
}
+ } else {
+ memset(buff, 0, iocommand.buf_size);
}
if ((c = cmd_alloc(host , 0)) == NULL)
{
/* Copy the error information out */
iocommand.error_info = *(c->err_info);
- if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) )
+ if ( copy_to_user(argp, &iocommand, sizeof( IOCTL_Command_struct) ) )
{
kfree(buff);
cmd_free(host, c, 0);
DECLARE_COMPLETION(wait);
__u32 left;
__u32 sz;
- BYTE *data_ptr;
+ BYTE __user *data_ptr;
if (!arg)
return -EINVAL;
status = -ENOMEM;
goto cleanup1;
}
- if (copy_from_user(ioc, (void *) arg, sizeof(*ioc))) {
+ if (copy_from_user(ioc, argp, sizeof(*ioc))) {
status = -EFAULT;
goto cleanup1;
}
goto cleanup1;
}
left = ioc->buf_size;
- data_ptr = (BYTE *) ioc->buf;
+ data_ptr = ioc->buf;
while (left) {
sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
buff_size[sg_used] = sz;
copy_from_user(buff[sg_used], data_ptr, sz)) {
status = -ENOMEM;
goto cleanup1;
+ } else {
+ memset(buff[sg_used], 0, sz);
}
left -= sz;
data_ptr += sz;
}
/* Copy the error information out */
ioc->error_info = *(c->err_info);
- if (copy_to_user((void *) arg, ioc, sizeof(*ioc))) {
+ if (copy_to_user(argp, ioc, sizeof(*ioc))) {
cmd_free(host, c, 0);
status = -EFAULT;
goto cleanup1;
}
if (ioc->Request.Type.Direction == XFER_READ) {
/* Copy the data out of the buffer we created */
- BYTE *ptr = (BYTE *) ioc->buf;
+ BYTE __user *ptr = ioc->buf;
for(i=0; i< sg_used; i++) {
if (copy_to_user(ptr, buff[i], buff_size[i])) {
cmd_free(host, c, 0);
drv->sectors = 32; // Sectors per track
drv->cylinders = total_size / 255 / 32;
} else {
+ unsigned int t;
+
drv->block_size = block_size;
drv->nr_blocks = total_size;
drv->heads = inq_buff->data_byte[6];
drv->sectors = inq_buff->data_byte[7];
drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8;
drv->cylinders += inq_buff->data_byte[5];
+ drv->raid_level = inq_buff->data_byte[8];
+ t = drv->heads * drv->sectors;
+ if (t > 1) {
+ drv->cylinders = total_size/t;
+ }
}
} else { /* Get geometry failed */
printk(KERN_WARNING "cciss: reading geometry failed, "
return_code = sendcmd(CCISS_READ_CAPACITY,
ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD);
if (return_code == IO_OK) {
- *total_size = be32_to_cpu(*((__u32 *) &buf->total_size[0]))+1;
- *block_size = be32_to_cpu(*((__u32 *) &buf->block_size[0]));
+ *total_size = be32_to_cpu(*((__be32 *) &buf->total_size[0]))+1;
+ *block_size = be32_to_cpu(*((__be32 *) &buf->block_size[0]));
} else { /* read capacity command failed */
printk(KERN_WARNING "cciss: read capacity failed\n");
*total_size = 0;
/*
* Map (physical) PCI mem into (virtual) kernel space
*/
-static ulong remap_pci_mem(ulong base, ulong size)
+static void __iomem *remap_pci_mem(ulong base, ulong size)
{
ulong page_base = ((ulong) base) & PAGE_MASK;
ulong page_offs = ((ulong) base) - page_base;
- ulong page_remapped = (ulong) ioremap(page_base, page_offs+size);
-
- return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL);
-}
-
-/*
- * Enqueuing and dequeuing functions for cmdlists.
- */
-static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c)
-{
- if (*Qptr == NULL) {
- *Qptr = c;
- c->next = c->prev = c;
- } else {
- c->prev = (*Qptr)->prev;
- c->next = (*Qptr);
- (*Qptr)->prev->next = c;
- (*Qptr)->prev = c;
- }
-}
+ void __iomem *page_remapped = ioremap(page_base, page_offs+size);
-static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
- CommandList_struct *c)
-{
- if (c && c->next != c) {
- if (*Qptr == c) *Qptr = c->next;
- c->prev->next = c->next;
- c->next->prev = c->prev;
- } else {
- *Qptr = NULL;
- }
- return c;
+ return page_remapped ? (page_remapped + page_offs) : NULL;
}
/*
static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
{
ushort subsystem_vendor_id, subsystem_device_id, command;
- unchar irq = pdev->irq;
__u32 board_id, scratchpad = 0;
__u64 cfg_offset;
__u32 cfg_base_addr;
#ifdef CCISS_DEBUG
printk("command = %x\n", command);
- printk("irq = %x\n", irq);
+ printk("irq = %x\n", pdev->irq);
printk("board_id = %x\n", board_id);
#endif /* CCISS_DEBUG */
- c->intr = irq;
+ c->intr = pdev->irq;
/*
* Memory base addr is first addr , the second points to the config
#ifdef CCISS_DEBUG
printk("cfg offset = %x\n", cfg_offset);
#endif /* CCISS_DEBUG */
- c->cfgtable = (CfgTable_struct *)
- remap_pci_mem(pci_resource_start(pdev, cfg_base_addr_index)
- + cfg_offset, sizeof(CfgTable_struct));
+ c->cfgtable = remap_pci_mem(pci_resource_start(pdev,
+ cfg_base_addr_index) + cfg_offset,
+ sizeof(CfgTable_struct));
c->board_id = board_id;
#ifdef CCISS_DEBUG
}
free_irq(hba[i]->intr, hba[i]);
pci_set_drvdata(pdev, NULL);
- iounmap((void*)hba[i]->vaddr);
+ iounmap(hba[i]->vaddr);
cciss_unregister_scsi(i); /* unhook from SCSI subsystem */
unregister_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname);
remove_proc_entry(hba[i]->devname, proc_cciss);
static int __init init_cciss_module(void)
{
+ register_cciss_ioctl32();
return ( cciss_init());
}
{
int i;
+ unregister_cciss_ioctl32();
pci_unregister_driver(&cciss_pci_driver);
/* double check that all controller entrys have been removed */
for (i=0; i< MAX_CTLR; i++)