*
* Linux MegaRAID device driver
*
- * Copyright © 2002 LSI Logic Corporation.
+ * Copyright (c) 2002 LSI Logic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* Copyright (c) 2003 Christoph Hellwig <hch@lst.de>
* - new-style, hotplug-aware pci probing and scsi registration
*
- * Version : v2.00.3 (Feb 19, 2003) - Atul Mukker <Atul.Mukker@lsil.com>
+ * Version : v2.00.4 Mon Nov 14 14:02:43 EST 2005 - Seokmann Ju
+ * <Seokmann.Ju@lsil.com>
*
* Description: Linux device driver for LSI Logic MegaRAID controller
*
* 518, 520, 531, 532
*
* This driver is supported by LSI Logic, with assistance from Red Hat, Dell,
- * and others. Please send updates to the public mailing list
- * linux-megaraid-devel@dell.com, and subscribe to and read archives of this
- * list at http://lists.us.dell.com/.
- *
- * For history of changes, see ChangeLog.megaraid.
+ * and others. Please send updates to the mailing list
+ * linux-scsi@vger.kernel.org .
*
*/
#include <linux/blkdev.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/reboot.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/dma-mapping.h>
#include <scsi/scsicam.h>
#include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
#include "megaraid.h"
-MODULE_AUTHOR ("LSI Logic Corporation");
-MODULE_DESCRIPTION ("LSI Logic MegaRAID driver");
+#define MEGARAID_MODULE_VERSION "2.00.4"
+
+MODULE_AUTHOR ("sju@lsil.com");
+MODULE_DESCRIPTION ("LSI Logic MegaRAID legacy driver");
MODULE_LICENSE ("GPL");
+MODULE_VERSION(MEGARAID_MODULE_VERSION);
static unsigned int max_cmd_per_lun = DEF_CMD_PER_LUN;
-MODULE_PARM(max_cmd_per_lun, "i");
+module_param(max_cmd_per_lun, uint, 0);
MODULE_PARM_DESC(max_cmd_per_lun, "Maximum number of commands which can be issued to a single LUN (default=DEF_CMD_PER_LUN=63)");
static unsigned short int max_sectors_per_io = MAX_SECTORS_PER_IO;
-MODULE_PARM(max_sectors_per_io, "h");
+module_param(max_sectors_per_io, ushort, 0);
MODULE_PARM_DESC(max_sectors_per_io, "Maximum number of sectors per I/O request (default=MAX_SECTORS_PER_IO=128)");
static unsigned short int max_mbox_busy_wait = MBOX_BUSY_WAIT;
-MODULE_PARM(max_mbox_busy_wait, "h");
+module_param(max_mbox_busy_wait, ushort, 0);
MODULE_PARM_DESC(max_mbox_busy_wait, "Maximum wait for mailbox in microseconds if busy (default=MBOX_BUSY_WAIT=10)");
-#define RDINDOOR(adapter) readl((adapter)->base + 0x20)
-#define RDOUTDOOR(adapter) readl((adapter)->base + 0x2C)
-#define WRINDOOR(adapter,value) writel(value, (adapter)->base + 0x20)
-#define WROUTDOOR(adapter,value) writel(value, (adapter)->base + 0x2C)
+#define RDINDOOR(adapter) readl((adapter)->mmio_base + 0x20)
+#define RDOUTDOOR(adapter) readl((adapter)->mmio_base + 0x2C)
+#define WRINDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x20)
+#define WROUTDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x2C)
/*
* Global variables
return 0;
}
+/**
+ * mega_runpendq()
+ * @adapter - pointer to our soft state
+ *
+ * Runs through the list of pending requests.
+ */
+static inline void
+mega_runpendq(adapter_t *adapter)
+{
+ if(!list_empty(&adapter->pending_list))
+ __mega_runpendq(adapter);
+}
/*
* megaraid_queue()
adapter_t *adapter;
scb_t *scb;
int busy=0;
+ unsigned long flags;
adapter = (adapter_t *)scmd->device->host->hostdata;
* return 0 in that case.
*/
+ spin_lock_irqsave(&adapter->lock, flags);
scb = mega_build_cmd(adapter, scmd, &busy);
+ if (!scb)
+ goto out;
- if(scb) {
- scb->state |= SCB_PENDQ;
- list_add_tail(&scb->list, &adapter->pending_list);
+ scb->state |= SCB_PENDQ;
+ list_add_tail(&scb->list, &adapter->pending_list);
- /*
- * Check if the HBA is in quiescent state, e.g., during a
- * delete logical drive opertion. If it is, don't run
- * the pending_list.
- */
- if(atomic_read(&adapter->quiescent) == 0) {
- mega_runpendq(adapter);
- }
- return 0;
- }
+ /*
+ * Check if the HBA is in quiescent state, e.g., during a
+ * delete logical drive opertion. If it is, don't run
+ * the pending_list.
+ */
+ if (atomic_read(&adapter->quiescent) == 0)
+ mega_runpendq(adapter);
+ busy = 0;
+ out:
+ spin_unlock_irqrestore(&adapter->lock, flags);
return busy;
}
+/**
+ * mega_allocate_scb()
+ * @adapter - pointer to our soft state
+ * @cmd - scsi command from the mid-layer
+ *
+ * Allocate a SCB structure. This is the central structure for controller
+ * commands.
+ */
+static inline scb_t *
+mega_allocate_scb(adapter_t *adapter, Scsi_Cmnd *cmd)
+{
+ struct list_head *head = &adapter->free_list;
+ scb_t *scb;
+
+ /* Unlink command from Free List */
+ if( !list_empty(head) ) {
+
+ scb = list_entry(head->next, scb_t, list);
+
+ list_del_init(head->next);
+
+ scb->state = SCB_ACTIVE;
+ scb->cmd = cmd;
+ scb->dma_type = MEGA_DMA_TYPE_NONE;
+
+ return scb;
+ }
+
+ return NULL;
+}
+
+/**
+ * mega_get_ldrv_num()
+ * @adapter - pointer to our soft state
+ * @cmd - scsi mid layer command
+ * @channel - channel on the controller
+ *
+ * Calculate the logical drive number based on the information in scsi command
+ * and the channel number.
+ */
+static inline int
+mega_get_ldrv_num(adapter_t *adapter, Scsi_Cmnd *cmd, int channel)
+{
+ int tgt;
+ int ldrv_num;
+
+ tgt = cmd->device->id;
+
+ if ( tgt > adapter->this_id )
+ tgt--; /* we do not get inquires for initiator id */
+
+ ldrv_num = (channel * 15) + tgt;
+
+
+ /*
+ * If we have a logical drive with boot enabled, project it first
+ */
+ if( adapter->boot_ldrv_enabled ) {
+ if( ldrv_num == 0 ) {
+ ldrv_num = adapter->boot_ldrv;
+ }
+ else {
+ if( ldrv_num <= adapter->boot_ldrv ) {
+ ldrv_num--;
+ }
+ }
+ }
+
+ /*
+ * If "delete logical drive" feature is enabled on this controller.
+ * Do only if at least one delete logical drive operation was done.
+ *
+ * Also, after logical drive deletion, instead of logical drive number,
+ * the value returned should be 0x80+logical drive id.
+ *
+ * These is valid only for IO commands.
+ */
+
+ if (adapter->support_random_del && adapter->read_ldidmap )
+ switch (cmd->cmnd[0]) {
+ case READ_6: /* fall through */
+ case WRITE_6: /* fall through */
+ case READ_10: /* fall through */
+ case WRITE_10:
+ ldrv_num += 0x80;
+ }
+
+ return ldrv_num;
+}
/**
* mega_build_cmd()
* filter the internal and ioctl commands
*/
if((cmd->cmnd[0] == MEGA_INTERNAL_CMD)) {
- return cmd->buffer;
+ return cmd->request_buffer;
}
if(islogical) {
switch (cmd->cmnd[0]) {
case TEST_UNIT_READY:
- memset(cmd->request_buffer, 0, cmd->request_bufflen);
-
#if MEGA_HAVE_CLUSTERING
/*
* Do we support clustering and is the support enabled
}
if(!(scb = mega_allocate_scb(adapter, cmd))) {
-
- cmd->result = (DID_ERROR << 16);
- cmd->scsi_done(cmd);
*busy = 1;
-
return NULL;
}
return NULL;
#endif
- case MODE_SENSE:
- memset(cmd->request_buffer, 0, cmd->cmnd[4]);
+ case MODE_SENSE: {
+ char *buf;
+
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *)cmd->request_buffer;
+ buf = kmap_atomic(sg->page, KM_IRQ0) +
+ sg->offset;
+ } else
+ buf = cmd->request_buffer;
+ memset(buf, 0, cmd->cmnd[4]);
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *)cmd->request_buffer;
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ }
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
+ }
case READ_CAPACITY:
case INQUIRY:
/* Allocate a SCB and initialize passthru */
if(!(scb = mega_allocate_scb(adapter, cmd))) {
-
- cmd->result = (DID_ERROR << 16);
- cmd->scsi_done(cmd);
*busy = 1;
-
return NULL;
}
pthru = scb->pthru;
/* Allocate a SCB and initialize mailbox */
if(!(scb = mega_allocate_scb(adapter, cmd))) {
-
- cmd->result = (DID_ERROR << 16);
- cmd->scsi_done(cmd);
*busy = 1;
-
return NULL;
}
mbox = (mbox_t *)scb->raw_mbox;
/* Allocate a SCB and initialize mailbox */
if(!(scb = mega_allocate_scb(adapter, cmd))) {
-
- cmd->result = (DID_ERROR << 16);
- cmd->scsi_done(cmd);
*busy = 1;
-
return NULL;
}
else {
/* Allocate a SCB and initialize passthru */
if(!(scb = mega_allocate_scb(adapter, cmd))) {
-
- cmd->result = (DID_ERROR << 16);
- cmd->scsi_done(cmd);
*busy = 1;
-
return NULL;
}
return epthru;
}
-
-/**
- * mega_allocate_scb()
- * @adapter - pointer to our soft state
- * @cmd - scsi command from the mid-layer
- *
- * Allocate a SCB structure. This is the central structure for controller
- * commands.
- */
-static inline scb_t *
-mega_allocate_scb(adapter_t *adapter, Scsi_Cmnd *cmd)
-{
- struct list_head *head = &adapter->free_list;
- scb_t *scb;
-
- /* Unlink command from Free List */
- if( !list_empty(head) ) {
-
- scb = list_entry(head->next, scb_t, list);
-
- list_del_init(head->next);
-
- scb->state = SCB_ACTIVE;
- scb->cmd = cmd;
- scb->dma_type = MEGA_DMA_TYPE_NONE;
-
- return scb;
- }
-
- return NULL;
-}
-
-
-/**
- * mega_runpendq()
- * @adapter - pointer to our soft state
- *
- * Runs through the list of pending requests.
- */
-static inline void
-mega_runpendq(adapter_t *adapter)
-{
- if(!list_empty(&adapter->pending_list))
- __mega_runpendq(adapter);
-}
-
static void
__mega_runpendq(adapter_t *adapter)
{
* busy. We also take the scb from the pending list if the mailbox is
* available.
*/
-static inline int
+static int
issue_scb(adapter_t *adapter, scb_t *scb)
{
volatile mbox64_t *mbox64 = adapter->mbox64;
return 0;
}
+/*
+ * Wait until the controller's mailbox is available
+ */
+static inline int
+mega_busywait_mbox (adapter_t *adapter)
+{
+ if (adapter->mbox->m_in.busy)
+ return __mega_busywait_mbox(adapter);
+ return 0;
+}
/**
* issue_scb_block()
* megaraid_isr_iomapped()
* @irq - irq
* @devp - pointer to our soft state
- * @regs - unused
*
* Interrupt service routine for io-mapped controllers.
* Find out if our device is interrupting. If yes, acknowledge the interrupt
* and service the completed commands.
*/
static irqreturn_t
-megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs)
+megaraid_isr_iomapped(int irq, void *devp)
{
adapter_t *adapter = devp;
unsigned long flags;
* megaraid_isr_memmapped()
* @irq - irq
* @devp - pointer to our soft state
- * @regs - unused
*
* Interrupt service routine for memory-mapped controllers.
* Find out if our device is interrupting. If yes, acknowledge the interrupt
* and service the completed commands.
*/
static irqreturn_t
-megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs)
+megaraid_isr_memmapped(int irq, void *devp)
{
adapter_t *adapter = devp;
unsigned long flags;
handled = 1;
- while( RDINDOOR(adapter) & 0x02 ) cpu_relax();
+ while( RDINDOOR(adapter) & 0x02 )
+ cpu_relax();
mega_cmd_done(adapter, completed, nstatus, status);
*
* Complete the comamnds and call the scsi mid-layer callback hooks.
*/
-static inline void
+static void
mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
{
mega_ext_passthru *epthru = NULL;
list_for_each(pos, &adapter->completed_list) {
- Scsi_Pointer* spos = (Scsi_Pointer *)pos;
+ struct scsi_pointer* spos = (struct scsi_pointer *)pos;
cmd = list_entry(spos, Scsi_Cmnd, SCp);
cmd->scsi_done(cmd);
static void
mega_free_scb(adapter_t *adapter, scb_t *scb)
{
+ unsigned long length;
+
switch( scb->dma_type ) {
case MEGA_DMA_TYPE_NONE:
break;
case MEGA_BULK_DATA:
+ if (scb->cmd->use_sg == 0)
+ length = scb->cmd->request_bufflen;
+ else {
+ struct scatterlist *sgl =
+ (struct scatterlist *)scb->cmd->request_buffer;
+ length = sgl->length;
+ }
pci_unmap_page(adapter->dev, scb->dma_h_bulkdata,
- scb->cmd->request_bufflen, scb->dma_direction);
+ length, scb->dma_direction);
break;
case MEGA_SGLIST:
}
-/*
- * Wait until the controller's mailbox is available
- */
-static inline int
-mega_busywait_mbox (adapter_t *adapter)
-{
- if (adapter->mbox->m_in.busy)
- return __mega_busywait_mbox(adapter);
- return 0;
-}
-
static int
__mega_busywait_mbox (adapter_t *adapter)
{
struct scatterlist *sgl;
struct page *page;
unsigned long offset;
+ unsigned int length;
Scsi_Cmnd *cmd;
int sgcnt;
int idx;
cmd = scb->cmd;
/* Scatter-gather not used */
- if( !cmd->use_sg ) {
-
- page = virt_to_page(cmd->request_buffer);
- offset = offset_in_page(cmd->request_buffer);
+ if( cmd->use_sg == 0 || (cmd->use_sg == 1 &&
+ !adapter->has_64bit_addr)) {
+
+ if (cmd->use_sg == 0) {
+ page = virt_to_page(cmd->request_buffer);
+ offset = offset_in_page(cmd->request_buffer);
+ length = cmd->request_bufflen;
+ } else {
+ sgl = (struct scatterlist *)cmd->request_buffer;
+ page = sgl->page;
+ offset = sgl->offset;
+ length = sgl->length;
+ }
scb->dma_h_bulkdata = pci_map_page(adapter->dev,
page, offset,
- cmd->request_bufflen,
+ length,
scb->dma_direction);
scb->dma_type = MEGA_BULK_DATA;
*/
if( adapter->has_64bit_addr ) {
scb->sgl64[0].address = scb->dma_h_bulkdata;
- scb->sgl64[0].length = cmd->request_bufflen;
+ scb->sgl64[0].length = length;
*buf = (u32)scb->sgl_dma_addr;
- *len = (u32)cmd->request_bufflen;
+ *len = (u32)length;
return 1;
}
else {
*buf = (u32)scb->dma_h_bulkdata;
- *len = (u32)cmd->request_bufflen;
+ *len = (u32)length;
}
return 0;
}
scb->dma_type = MEGA_SGLIST;
- if( sgcnt > adapter->sglen ) BUG();
+ BUG_ON(sgcnt > adapter->sglen);
+
+ *len = 0;
for( idx = 0; idx < sgcnt; idx++, sgl++ ) {
if( adapter->has_64bit_addr ) {
scb->sgl64[idx].address = sg_dma_address(sgl);
- scb->sgl64[idx].length = sg_dma_len(sgl);
+ *len += scb->sgl64[idx].length = sg_dma_len(sgl);
}
else {
scb->sgl[idx].address = sg_dma_address(sgl);
- scb->sgl[idx].length = sg_dma_len(sgl);
+ *len += scb->sgl[idx].length = sg_dma_len(sgl);
}
}
/* Reset pointer and length fields */
*buf = scb->sgl_dma_addr;
- /*
- * For passthru command, dataxferlen must be set, even for commands
- * with a sg list
- */
- *len = (u32)cmd->request_bufflen;
-
/* Return count of SG requests */
return sgcnt;
}
static int
-megaraid_reset(Scsi_Cmnd *cmd)
+megaraid_reset(struct scsi_cmnd *cmd)
{
adapter_t *adapter;
megacmd_t mc;
mc.cmd = MEGA_CLUSTER_CMD;
mc.opcode = MEGA_RESET_RESERVATIONS;
- spin_unlock_irq(&adapter->lock);
- if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) != 0 ) {
+ if( mega_internal_command(adapter, &mc, NULL) != 0 ) {
printk(KERN_WARNING
"megaraid: reservation reset failed.\n");
}
else {
printk(KERN_INFO "megaraid: reservation reset.\n");
}
- spin_lock_irq(&adapter->lock);
#endif
+ spin_lock_irq(&adapter->lock);
+
rval = megaraid_abort_and_reset(adapter, cmd, SCB_RESET);
/*
* to be communicated over to the mid layer.
*/
mega_rundoneq(adapter);
+ spin_unlock_irq(&adapter->lock);
return rval;
}
-
-
/**
* megaraid_abort_and_reset()
* @adapter - megaraid soft state
return FALSE;
}
+static inline int
+make_local_pdev(adapter_t *adapter, struct pci_dev **pdev)
+{
+ *pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+
+ if( *pdev == NULL ) return -1;
+
+ memcpy(*pdev, adapter->dev, sizeof(struct pci_dev));
+
+ if( pci_set_dma_mask(*pdev, DMA_32BIT_MASK) != 0 ) {
+ kfree(*pdev);
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline void
+free_local_pdev(struct pci_dev *pdev)
+{
+ kfree(pdev);
+}
+
+/**
+ * mega_allocate_inquiry()
+ * @dma_handle - handle returned for dma address
+ * @pdev - handle to pci device
+ *
+ * allocates memory for inquiry structure
+ */
+static inline void *
+mega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev)
+{
+ return pci_alloc_consistent(pdev, sizeof(mega_inquiry3), dma_handle);
+}
+
+
+static inline void
+mega_free_inquiry(void *inquiry, dma_addr_t dma_handle, struct pci_dev *pdev)
+{
+ pci_free_consistent(pdev, sizeof(mega_inquiry3), inquiry, dma_handle);
+}
+
#ifdef CONFIG_PROC_FS
/* Following code handles /proc fs */
i = scsi_inq[0] & 0x1f;
- len += sprintf(page+len, " Type: %s ",
- i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
- "Unknown ");
+ len += sprintf(page+len, " Type: %s ", scsi_device_type(i));
len += sprintf(page+len,
" ANSI SCSI revision: %02x", scsi_inq[2] & 0x07);
mc.cmd = FC_NEW_CONFIG;
mc.opcode = OP_DCMD_READ_CONFIG;
- if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) ) {
+ if( mega_internal_command(adapter, &mc, NULL) ) {
len = sprintf(page, "40LD read config failed.\n");
else {
mc.cmd = NEW_READ_CONFIG_8LD;
- if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) ) {
+ if( mega_internal_command(adapter, &mc, NULL) ) {
mc.cmd = READ_CONFIG_8LD;
- if( mega_internal_command(adapter, LOCK_INT, &mc,
+ if( mega_internal_command(adapter, &mc,
NULL) ){
len = sprintf(page,
nitioctl_t uioc;
int adapno;
int rval;
- mega_passthru *upthru; /* user address for passthru */
+ mega_passthru __user *upthru; /* user address for passthru */
mega_passthru *pthru; /* copy user passthru here */
dma_addr_t pthru_dma_hndl;
void *data = NULL; /* data to be transferred */
dma_addr_t data_dma_hndl; /* dma handle for data xfer area */
megacmd_t mc;
- megastat_t *ustats;
+ megastat_t __user *ustats;
int num_ldrv;
u32 uxferaddr = 0;
struct pci_dev *pdev;
* addresses.
*/
memset(&uioc, 0, sizeof(nitioctl_t));
- if( (rval = mega_m_to_n( (void *)arg, &uioc)) != 0 )
+ if( (rval = mega_m_to_n( (void __user *)arg, &uioc)) != 0 )
return rval;
switch( uioc.opcode ) {
case GET_DRIVER_VER:
- if( put_user(driver_ver, (u32 *)uioc.uioc_uaddr) )
+ if( put_user(driver_ver, (u32 __user *)uioc.uioc_uaddr) )
return (-EFAULT);
break;
case GET_N_ADAP:
- if( put_user(hba_count, (u32 *)uioc.uioc_uaddr) )
+ if( put_user(hba_count, (u32 __user *)uioc.uioc_uaddr) )
return (-EFAULT);
/*
adapter = hba_soft_state[adapno];
- ustats = (megastat_t *)uioc.uioc_uaddr;
+ ustats = uioc.uioc_uaddr;
if( copy_from_user(&num_ldrv, &ustats->num_ldrv, sizeof(int)) )
return (-EFAULT);
mc.status = rval;
- rval = mega_n_to_m((void *)arg, &mc);
+ rval = mega_n_to_m((void __user *)arg, &mc);
}
return rval;
/*
* The user passthru structure
*/
- upthru = (mega_passthru *)MBOX(uioc)->xferaddr;
+ upthru = (mega_passthru __user *)MBOX(uioc)->xferaddr;
/*
* Copy in the user passthru here.
*/
- if( copy_from_user(pthru, (char *)upthru,
+ if( copy_from_user(pthru, upthru,
sizeof(mega_passthru)) ) {
pci_free_consistent(pdev,
/*
* Get the user data
*/
- if( copy_from_user(data, (char *)uxferaddr,
+ if( copy_from_user(data, (char __user *)uxferaddr,
pthru->dataxferlen) ) {
rval = (-EFAULT);
goto freemem_and_return;
/*
* Issue the command
*/
- mega_internal_command(adapter, LOCK_INT, &mc, pthru);
+ mega_internal_command(adapter, &mc, pthru);
- rval = mega_n_to_m((void *)arg, &mc);
+ rval = mega_n_to_m((void __user *)arg, &mc);
if( rval ) goto freemem_and_return;
* Is data going up-stream
*/
if( pthru->dataxferlen && (uioc.flags & UIOC_RD) ) {
- if( copy_to_user((char *)uxferaddr, data,
+ if( copy_to_user((char __user *)uxferaddr, data,
pthru->dataxferlen) ) {
rval = (-EFAULT);
}
* Send the request sense data also, irrespective of
* whether the user has asked for it or not.
*/
- copy_to_user(upthru->reqsensearea,
- pthru->reqsensearea, 14);
+ if (copy_to_user(upthru->reqsensearea,
+ pthru->reqsensearea, 14))
+ rval = -EFAULT;
freemem_and_return:
if( pthru->dataxferlen ) {
/*
* Get the user data
*/
- if( copy_from_user(data, (char *)uxferaddr,
+ if( copy_from_user(data, (char __user *)uxferaddr,
uioc.xferlen) ) {
pci_free_consistent(pdev,
/*
* Issue the command
*/
- mega_internal_command(adapter, LOCK_INT, &mc, NULL);
+ mega_internal_command(adapter, &mc, NULL);
- rval = mega_n_to_m((void *)arg, &mc);
+ rval = mega_n_to_m((void __user *)arg, &mc);
if( rval ) {
if( uioc.xferlen ) {
* Is data going up-stream
*/
if( uioc.xferlen && (uioc.flags & UIOC_RD) ) {
- if( copy_to_user((char *)uxferaddr, data,
+ if( copy_to_user((char __user *)uxferaddr, data,
uioc.xferlen) ) {
rval = (-EFAULT);
* Converts the older mimd ioctl structure to newer NIT structure
*/
static int
-mega_m_to_n(void *arg, nitioctl_t *uioc)
+mega_m_to_n(void __user *arg, nitioctl_t *uioc)
{
struct uioctl_t uioc_mimd;
char signature[8] = {0};
* begining of the structure.
*/
- if( copy_from_user(signature, (char *)arg, 7) )
+ if( copy_from_user(signature, arg, 7) )
return (-EFAULT);
if( memcmp(signature, "MEGANIT", 7) == 0 ) {
*/
return -EINVAL;
#if 0
- if( copy_from_user(uioc, (char *)arg, sizeof(nitioctl_t)) )
+ if( copy_from_user(uioc, arg, sizeof(nitioctl_t)) )
return (-EFAULT);
return 0;
#endif
*
* Get the user ioctl structure
*/
- if( copy_from_user(&uioc_mimd, (char *)arg, sizeof(struct uioctl_t)) )
+ if( copy_from_user(&uioc_mimd, arg, sizeof(struct uioctl_t)) )
return (-EFAULT);
* conforms to older mimd ioctl interface or newer NIT ioctl interface
*/
static int
-mega_n_to_m(void *arg, megacmd_t *mc)
+mega_n_to_m(void __user *arg, megacmd_t *mc)
{
- nitioctl_t *uiocp;
- megacmd_t *umc;
- mega_passthru *upthru;
- struct uioctl_t *uioc_mimd;
+ nitioctl_t __user *uiocp;
+ megacmd_t __user *umc;
+ mega_passthru __user *upthru;
+ struct uioctl_t __user *uioc_mimd;
char signature[8] = {0};
/*
* check is the application conforms to NIT.
*/
- if( copy_from_user(signature, (char *)arg, 7) )
+ if( copy_from_user(signature, arg, 7) )
return -EFAULT;
if( memcmp(signature, "MEGANIT", 7) == 0 ) {
- uiocp = (nitioctl_t *)arg;
+ uiocp = arg;
- if( put_user(mc->status, (u8 *)&MBOX_P(uiocp)->status) )
+ if( put_user(mc->status, (u8 __user *)&MBOX_P(uiocp)->status) )
return (-EFAULT);
if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
umc = MBOX_P(uiocp);
- upthru = (mega_passthru *)umc->xferaddr;
+ if (get_user(upthru, (mega_passthru __user * __user *)&umc->xferaddr))
+ return -EFAULT;
- if( put_user(mc->status, (u8 *)&upthru->scsistatus) )
+ if( put_user(mc->status, (u8 __user *)&upthru->scsistatus))
return (-EFAULT);
}
}
else {
- uioc_mimd = (struct uioctl_t *)arg;
+ uioc_mimd = arg;
- if( put_user(mc->status, (u8 *)&uioc_mimd->mbox[17]) )
+ if( put_user(mc->status, (u8 __user *)&uioc_mimd->mbox[17]) )
return (-EFAULT);
if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
- umc = (megacmd_t *)uioc_mimd->mbox;
+ umc = (megacmd_t __user *)uioc_mimd->mbox;
- upthru = (mega_passthru *)umc->xferaddr;
+ if (get_user(upthru, (mega_passthru __user * __user *)&umc->xferaddr))
+ return (-EFAULT);
- if( put_user(mc->status, (u8 *)&upthru->scsistatus) )
+ if( put_user(mc->status, (u8 __user *)&upthru->scsistatus) )
return (-EFAULT);
}
}
mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
/*
- * Non-ROMB firware fail this command, so all channels
+ * Non-ROMB firmware fail this command, so all channels
* must be shown RAID
*/
adapter->mega_ch_class = 0xFF;
static int
mega_del_logdrv(adapter_t *adapter, int logdrv)
{
- DECLARE_WAIT_QUEUE_HEAD(wq);
unsigned long flags;
scb_t *scb;
int rval;
* Wait till all the issued commands are complete and there are no
* commands in the pending queue
*/
- while( atomic_read(&adapter->pend_cmds) > 0 ||
- !list_empty(&adapter->pending_list) ) {
-
- sleep_on_timeout( &wq, 1*HZ ); /* sleep for 1s */
- }
+ while (atomic_read(&adapter->pend_cmds) > 0 ||
+ !list_empty(&adapter->pending_list))
+ msleep(1000); /* sleep for 1s */
rval = mega_do_del_logdrv(adapter, logdrv);
mc.opcode = OP_DEL_LOGDRV;
mc.subopcode = logdrv;
- rval = mega_internal_command(adapter, LOCK_INT, &mc, NULL);
+ rval = mega_internal_command(adapter, &mc, NULL);
/* log this event */
if(rval) {
}
-
-/**
- * mega_get_ldrv_num()
- * @adapter - pointer to our soft state
- * @cmd - scsi mid layer command
- * @channel - channel on the controller
- *
- * Calculate the logical drive number based on the information in scsi command
- * and the channel number.
- */
-static inline int
-mega_get_ldrv_num(adapter_t *adapter, Scsi_Cmnd *cmd, int channel)
-{
- int tgt;
- int ldrv_num;
-
- tgt = cmd->device->id;
-
- if ( tgt > adapter->this_id )
- tgt--; /* we do not get inquires for initiator id */
-
- ldrv_num = (channel * 15) + tgt;
-
-
- /*
- * If we have a logical drive with boot enabled, project it first
- */
- if( adapter->boot_ldrv_enabled ) {
- if( ldrv_num == 0 ) {
- ldrv_num = adapter->boot_ldrv;
- }
- else {
- if( ldrv_num <= adapter->boot_ldrv ) {
- ldrv_num--;
- }
- }
- }
-
- /*
- * If "delete logical drive" feature is enabled on this controller.
- * Do only if at least one delete logical drive operation was done.
- *
- * Also, after logical drive deletion, instead of logical drive number,
- * the value returned should be 0x80+logical drive id.
- *
- * These is valid only for IO commands.
- */
-
- if (adapter->support_random_del && adapter->read_ldidmap )
- switch (cmd->cmnd[0]) {
- case READ_6: /* fall through */
- case WRITE_6: /* fall through */
- case READ_10: /* fall through */
- case WRITE_10:
- ldrv_num += 0x80;
- }
-
- return ldrv_num;
-}
-
-
/**
* mega_adapinq()
* @adapter - pointer to our soft state
mc.xferaddr = (u32)dma_handle;
- if ( mega_internal_command(adapter, LOCK_INT, &mc, NULL) != 0 ) {
+ if ( mega_internal_command(adapter, &mc, NULL) != 0 ) {
return -1;
}
}
-/**
- * mega_allocate_inquiry()
- * @dma_handle - handle returned for dma address
- * @pdev - handle to pci device
- *
- * allocates memory for inquiry structure
- */
-static inline caddr_t
-mega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev)
-{
- return pci_alloc_consistent(pdev, sizeof(mega_inquiry3), dma_handle);
-}
-
-
-static inline void
-mega_free_inquiry(caddr_t inquiry, dma_addr_t dma_handle, struct pci_dev *pdev)
-{
- pci_free_consistent(pdev, sizeof(mega_inquiry3), inquiry, dma_handle);
-}
-
-
/** mega_internal_dev_inquiry()
* @adapter - pointer to our soft state
* @ch - channel for this device
mc.cmd = MEGA_MBOXCMD_PASSTHRU;
mc.xferaddr = (u32)pthru_dma_handle;
- rval = mega_internal_command(adapter, LOCK_INT, &mc, pthru);
+ rval = mega_internal_command(adapter, &mc, pthru);
pci_free_consistent(pdev, sizeof(mega_passthru), pthru,
pthru_dma_handle);
/**
* mega_internal_command()
* @adapter - pointer to our soft state
- * @ls - the scope of the exclusion lock.
* @mc - the mailbox command
* @pthru - Passthru structure for DCDB commands
*
* Note: parameter 'pthru' is null for non-passthru commands.
*/
static int
-mega_internal_command(adapter_t *adapter, lockscope_t ls, megacmd_t *mc,
- mega_passthru *pthru )
+mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
{
Scsi_Cmnd *scmd;
struct scsi_device *sdev;
- unsigned long flags = 0;
scb_t *scb;
int rval;
* serialized. This is so because we want to reserve maximum number of
* available command ids for the I/O commands.
*/
- down(&adapter->int_mtx);
+ mutex_lock(&adapter->int_mtx);
scb = &adapter->int_scb;
memset(scb, 0, sizeof(scb_t));
scmd->device = sdev;
scmd->device->host = adapter->host;
- scmd->buffer = (void *)scb;
+ scmd->request_buffer = (void *)scb;
scmd->cmnd[0] = MEGA_INTERNAL_CMD;
scb->state |= SCB_ACTIVE;
scb->idx = CMDID_INT_CMDS;
- scmd->state = 0;
-
- /*
- * Get the lock only if the caller has not acquired it already
- */
- if( ls == LOCK_INT ) spin_lock_irqsave(&adapter->lock, flags);
-
megaraid_queue(scmd, mega_internal_done);
- if( ls == LOCK_INT ) spin_unlock_irqrestore(&adapter->lock, flags);
-
- /*
- * Wait till this command finishes. Do not use
- * wait_event_interruptible(). It causes panic if CTRL-C is hit when
- * dumping e.g., physical disk information through /proc interface.
- */
-#if 0
- wait_event_interruptible(adapter->int_waitq, scmd->state);
-#endif
- wait_event(adapter->int_waitq, scmd->state);
+ wait_for_completion(&adapter->int_waitq);
rval = scmd->result;
mc->status = scmd->result;
mc->cmd, mc->opcode, mc->subopcode, scmd->result);
}
- up(&adapter->int_mtx);
+ mutex_unlock(&adapter->int_mtx);
return rval;
}
adapter = (adapter_t *)scmd->device->host->hostdata;
- scmd->state = 1; /* thread waiting for its command to complete */
-
- /*
- * See comment in mega_internal_command() routine for
- * wait_event_interruptible()
- */
-#if 0
- wake_up_interruptible(&adapter->int_waitq);
-#endif
- wake_up(&adapter->int_waitq);
-
-}
-
-
-static inline int
-make_local_pdev(adapter_t *adapter, struct pci_dev **pdev)
-{
- *pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
-
- if( *pdev == NULL ) return -1;
-
- memcpy(*pdev, adapter->dev, sizeof(struct pci_dev));
-
- if( pci_set_dma_mask(*pdev, 0xffffffff) != 0 ) {
- kfree(*pdev);
- return -1;
- }
+ complete(&adapter->int_waitq);
- return 0;
}
-static inline void
-free_local_pdev(struct pci_dev *pdev)
-{
- kfree(pdev);
-}
static struct scsi_host_template megaraid_template = {
.module = THIS_MODULE,
.name = "MegaRAID",
- .proc_name = "megaraid",
+ .proc_name = "megaraid_legacy",
.info = megaraid_info,
.queuecommand = megaraid_queue,
.bios_param = megaraid_biosparam,
if (pci_enable_device(pdev))
goto out;
+ pci_set_master(pdev);
pci_bus = pdev->bus->number;
pci_dev_func = pdev->devfn;
+ /*
+ * The megaraid3 stuff reports the ID of the Intel part which is not
+ * remotely specific to the megaraid
+ */
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+ u16 magic;
+ /*
+ * Don't fall over the Compaq management cards using the same
+ * PCI identifier
+ */
+ if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ &&
+ pdev->subsystem_device == 0xC000)
+ return -ENODEV;
+ /* Now check the magic signature byte */
+ pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic);
+ if (magic != HBA_SIGNATURE_471 && magic != HBA_SIGNATURE)
+ return -ENODEV;
+ /* Ok it is probably a megaraid */
+ }
+
/*
* For these vendor and device ids, signature offsets are not
* valid and 64 bit is implicit
host->host_no, mega_baseport, irq);
adapter->base = mega_baseport;
+ if (flag & BOARD_MEMMAP)
+ adapter->mmio_base = (void __iomem *) mega_baseport;
INIT_LIST_HEAD(&adapter->free_list);
INIT_LIST_HEAD(&adapter->pending_list);
adapter->flag = flag;
spin_lock_init(&adapter->lock);
- scsi_assign_lock(host, &adapter->lock);
host->cmd_per_lun = max_cmd_per_lun;
host->max_sectors = max_sectors_per_io;
if (request_irq(irq, (adapter->flag & BOARD_MEMMAP) ?
megaraid_isr_memmapped : megaraid_isr_iomapped,
- SA_SHIRQ, "megaraid", adapter)) {
+ IRQF_SHARED, "megaraid", adapter)) {
printk(KERN_WARNING
"megaraid: Couldn't register IRQ %d!\n", irq);
goto out_free_scb_list;
/* Set the Mode of addressing to 64 bit if we can */
if ((adapter->flag & BOARD_64BIT) && (sizeof(dma_addr_t) == 8)) {
- pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+ pci_set_dma_mask(pdev, DMA_64BIT_MASK);
adapter->has_64bit_addr = 1;
} else {
- pci_set_dma_mask(pdev, 0xffffffff);
+ pci_set_dma_mask(pdev, DMA_32BIT_MASK);
adapter->has_64bit_addr = 0;
}
- init_MUTEX(&adapter->int_mtx);
- init_waitqueue_head(&adapter->int_waitq);
+ mutex_init(&adapter->int_mtx);
+ init_completion(&adapter->int_waitq);
adapter->this_id = DEFAULT_INITIATOR_ID;
adapter->host->this_id = DEFAULT_INITIATOR_ID;
}
static void
-megaraid_shutdown(struct device *dev)
+megaraid_shutdown(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
adapter_t *adapter = (adapter_t *)host->hostdata;
__megaraid_shutdown(adapter);
}
static struct pci_device_id megaraid_pci_tbl[] = {
- {PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DISCOVERY,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_PERC4_DI,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, BOARD_64BIT},
- {PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_PERC4_QC_VERDE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, BOARD_64BIT},
{PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID3,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_AMI_MEGARAID3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_AMI_MEGARAID3,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};
MODULE_DEVICE_TABLE(pci, megaraid_pci_tbl);
static struct pci_driver megaraid_pci_driver = {
- .name = "megaraid",
+ .name = "megaraid_legacy",
.id_table = megaraid_pci_tbl,
.probe = megaraid_probe_one,
.remove = __devexit_p(megaraid_remove_one),
- .driver = {
- .shutdown = megaraid_shutdown,
- },
+ .shutdown = megaraid_shutdown,
};
static int __init megaraid_init(void)
* First argument (major) to register_chrdev implies a dynamic
* major number allocation.
*/
- major = register_chrdev(0, "megadev", &megadev_fops);
+ major = register_chrdev(0, "megadev_legacy", &megadev_fops);
if (!major) {
printk(KERN_WARNING
"megaraid: failed to register char device\n");
/*
* Unregister the character device interface to the driver.
*/
- unregister_chrdev(major, "megadev");
+ unregister_chrdev(major, "megadev_legacy");
+
+ pci_unregister_driver(&megaraid_pci_driver);
#ifdef CONFIG_PROC_FS
remove_proc_entry("megaraid", &proc_root);
#endif
-
- pci_unregister_driver(&megaraid_pci_driver);
}
module_init(megaraid_init);