*
* 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
*
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/smp_lock.h>
#include <scsi/scsicam.h>
#include "scsi.h"
#include "megaraid.h"
-#define MEGARAID_MODULE_VERSION "2.00.3"
+#define MEGARAID_MODULE_VERSION "2.00.4"
-MODULE_AUTHOR ("LSI Logic Corporation");
-MODULE_DESCRIPTION ("LSI Logic MegaRAID driver");
+MODULE_AUTHOR ("sju@lsil.com");
+MODULE_DESCRIPTION ("LSI Logic MegaRAID legacy driver");
MODULE_LICENSE ("GPL");
MODULE_VERSION(MEGARAID_MODULE_VERSION);
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
/*
* The File Operations structure for the serial/ioctl interface of the driver
*/
-static struct file_operations megadev_fops = {
+static const struct file_operations megadev_fops = {
.owner = THIS_MODULE,
.ioctl = megadev_ioctl,
.open = megadev_open,
*/
if( adapter->flag & BOARD_IOMAP ) {
- outb_p(adapter->mbox_dma & 0xFF,
+ outb(adapter->mbox_dma & 0xFF,
adapter->host->io_port + MBOX_PORT0);
- outb_p((adapter->mbox_dma >> 8) & 0xFF,
+ outb((adapter->mbox_dma >> 8) & 0xFF,
adapter->host->io_port + MBOX_PORT1);
- outb_p((adapter->mbox_dma >> 16) & 0xFF,
+ outb((adapter->mbox_dma >> 16) & 0xFF,
adapter->host->io_port + MBOX_PORT2);
- outb_p((adapter->mbox_dma >> 24) & 0xFF,
+ outb((adapter->mbox_dma >> 24) & 0xFF,
adapter->host->io_port + MBOX_PORT3);
- outb_p(ENABLE_MBOX_BYTE,
+ outb(ENABLE_MBOX_BYTE,
adapter->host->io_port + ENABLE_MBOX_REGION);
irq_ack(adapter);
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;
- }
- spin_unlock_irqrestore(&adapter->lock, flags);
+ /*
+ * 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;
}
/*
* filter the internal and ioctl commands
*/
- if((cmd->cmnd[0] == MEGA_INTERNAL_CMD)) {
- return cmd->buffer;
- }
-
+ if((cmd->cmnd[0] == MEGA_INTERNAL_CMD))
+ return (scb_t *)cmd->host_scribble;
/*
* We know what channels our logical drives are on - mega_find_card()
case MODE_SENSE: {
char *buf;
+ struct scatterlist *sg;
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ sg = scsi_sglist(cmd);
+ buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
- sg = (struct scatterlist *)cmd->request_buffer;
- buf = kmap_atomic(sg->page, KM_IRQ0) +
- sg->offset;
- } else
- buf = cmd->request_buffer;
- memset(cmd->request_buffer, 0, cmd->cmnd[4]);
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ memset(buf, 0, cmd->cmnd[4]);
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
- sg = (struct scatterlist *)cmd->request_buffer;
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
- }
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
* 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);
islogical = adapter->logdrv_chan[cmd->device->channel];
if( cmd->cmnd[0] == INQUIRY && !islogical ) {
- if( cmd->use_sg ) {
- sgl = (struct scatterlist *)
- cmd->request_buffer;
-
- if( sgl->page ) {
- c = *(unsigned char *)
- page_address((&sgl[0])->page) +
- (&sgl[0])->offset;
- }
- else {
- printk(KERN_WARNING
- "megaraid: invalid sg.\n");
- c = 0;
- }
- }
- else {
- c = *(u8 *)cmd->request_buffer;
+ sgl = scsi_sglist(cmd);
+ if( sg_page(sgl) ) {
+ c = *(unsigned char *) sg_virt(&sgl[0]);
+ } else {
+ printk(KERN_WARNING
+ "megaraid: invalid sg.\n");
+ c = 0;
}
if(IS_RAID_CH(adapter, cmd->device->channel) &&
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,
- length, scb->dma_direction);
- break;
-
case MEGA_SGLIST:
- pci_unmap_sg(adapter->dev, scb->cmd->request_buffer,
- scb->cmd->use_sg, scb->dma_direction);
+ scsi_dma_unmap(scb->cmd);
break;
-
default:
break;
}
for (counter = 0; counter < 10000; counter++) {
if (!mbox->m_in.busy)
return 0;
- udelay(100); yield();
+ udelay(100);
+ cond_resched();
}
return -1; /* give up after 1 second */
}
static int
mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len)
{
- struct scatterlist *sgl;
- struct page *page;
- unsigned long offset;
- unsigned int length;
+ struct scatterlist *sg;
Scsi_Cmnd *cmd;
int sgcnt;
int idx;
cmd = scb->cmd;
- /* Scatter-gather not used */
- 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,
- length,
- scb->dma_direction);
- scb->dma_type = MEGA_BULK_DATA;
-
- /*
- * We need to handle special 64-bit commands that need a
- * minimum of 1 SG
- */
- if( adapter->has_64bit_addr ) {
- scb->sgl64[0].address = scb->dma_h_bulkdata;
- scb->sgl64[0].length = length;
- *buf = (u32)scb->sgl_dma_addr;
- *len = (u32)length;
- return 1;
- }
- else {
- *buf = (u32)scb->dma_h_bulkdata;
- *len = (u32)length;
- }
- return 0;
- }
-
- sgl = (struct scatterlist *)cmd->request_buffer;
-
/*
* Copy Scatter-Gather list info into controller structure.
*
* The number of sg elements returned must not exceed our limit
*/
- sgcnt = pci_map_sg(adapter->dev, sgl, cmd->use_sg,
- scb->dma_direction);
+ sgcnt = scsi_dma_map(cmd);
scb->dma_type = MEGA_SGLIST;
- if( sgcnt > adapter->sglen ) BUG();
+ BUG_ON(sgcnt > adapter->sglen || sgcnt < 0);
*len = 0;
- for( idx = 0; idx < sgcnt; idx++, sgl++ ) {
+ if (scsi_sg_count(cmd) == 1 && !adapter->has_64bit_addr) {
+ sg = scsi_sglist(cmd);
+ scb->dma_h_bulkdata = sg_dma_address(sg);
+ *buf = (u32)scb->dma_h_bulkdata;
+ *len = sg_dma_len(sg);
+ return 0;
+ }
- if( adapter->has_64bit_addr ) {
- scb->sgl64[idx].address = sg_dma_address(sgl);
- *len += scb->sgl64[idx].length = sg_dma_len(sgl);
- }
- else {
- scb->sgl[idx].address = sg_dma_address(sgl);
- *len += scb->sgl[idx].length = sg_dma_len(sgl);
+ scsi_for_each_sg(cmd, sg, sgcnt, idx) {
+ if (adapter->has_64bit_addr) {
+ scb->sgl64[idx].address = sg_dma_address(sg);
+ *len += scb->sgl64[idx].length = sg_dma_len(sg);
+ } else {
+ scb->sgl[idx].address = sg_dma_address(sg);
+ *len += scb->sgl[idx].length = sg_dma_len(sg);
}
}
scb->state |= aor;
/*
- * Check if this command has firmare owenership. If
- * yes, we cannot reset this command. Whenever, f/w
+ * Check if this command has firmware ownership. If
+ * yes, we cannot reset this command. Whenever f/w
* completes this command, we will return appropriate
* status from ISR.
*/
static inline int
make_local_pdev(adapter_t *adapter, struct pci_dev **pdev)
{
- *pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+ *pdev = alloc_pci_dev();
if( *pdev == NULL ) return -1;
memcpy(*pdev, adapter->dev, sizeof(struct pci_dev));
- if( pci_set_dma_mask(*pdev, 0xffffffff) != 0 ) {
+ if( pci_set_dma_mask(*pdev, DMA_BIT_MASK(32)) != 0 ) {
kfree(*pdev);
return -1;
}
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);
return len;
}
-
+#else
+static inline void mega_create_proc_entry(int index, struct proc_dir_entry *parent)
+{
+}
#endif
* @filep - unused
*
* Routines for the character/ioctl interface to the driver. Find out if this
- * is a valid open. If yes, increment the module use count so that it cannot
- * be unloaded.
+ * is a valid open.
*/
static int
megadev_open (struct inode *inode, struct file *filep)
{
+ cycle_kernel_lock();
/*
* Only allow superuser to access private ioctl interface
*/
/*
* The user passthru structure
*/
- upthru = (mega_passthru __user *)MBOX(uioc)->xferaddr;
+ upthru = (mega_passthru __user *)(unsigned long)MBOX(uioc)->xferaddr;
/*
* Copy in the user passthru here.
/*
* Get the user data
*/
- if( copy_from_user(data, (char __user *)uxferaddr,
+ if( copy_from_user(data, (char __user *)(unsigned long) uxferaddr,
pthru->dataxferlen) ) {
rval = (-EFAULT);
goto freemem_and_return;
* Is data going up-stream
*/
if( pthru->dataxferlen && (uioc.flags & UIOC_RD) ) {
- if( copy_to_user((char __user *)uxferaddr, data,
+ if( copy_to_user((char __user *)(unsigned long) 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 __user *)uxferaddr,
+ if( copy_from_user(data, (char __user *)(unsigned long) uxferaddr,
uioc.xferlen) ) {
pci_free_consistent(pdev,
* Is data going up-stream
*/
if( uioc.xferlen && (uioc.flags & UIOC_RD) ) {
- if( copy_to_user((char __user *)uxferaddr, data,
+ if( copy_to_user((char __user *)(unsigned long) uxferaddr, data,
uioc.xferlen) ) {
rval = (-EFAULT);
return 0;
}
-
+#ifdef CONFIG_PROC_FS
/**
* mega_adapinq()
* @adapter - pointer to our soft state
return rval;
}
-
+#endif
/**
* mega_internal_command()
{
Scsi_Cmnd *scmd;
struct scsi_device *sdev;
- unsigned long flags = 0;
scb_t *scb;
int rval;
+ scmd = scsi_allocate_command(GFP_KERNEL);
+ if (!scmd)
+ return -ENOMEM;
+
/*
* The internal commands share one command id and hence are
* 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 = &adapter->int_scmd;
- memset(scmd, 0, sizeof(Scsi_Cmnd));
-
- sdev = kmalloc(sizeof(struct scsi_device), GFP_KERNEL);
- memset(sdev, 0, sizeof(struct scsi_device));
+ sdev = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
scmd->device = sdev;
+ memset(adapter->int_cdb, 0, sizeof(adapter->int_cdb));
+ scmd->cmnd = adapter->int_cdb;
scmd->device->host = adapter->host;
- scmd->buffer = (void *)scb;
+ scmd->host_scribble = (void *)scb;
scmd->cmnd[0] = MEGA_INTERNAL_CMD;
scb->state |= SCB_ACTIVE;
mc->cmd, mc->opcode, mc->subopcode, scmd->result);
}
- up(&adapter->int_mtx);
+ mutex_unlock(&adapter->int_mtx);
+
+ scsi_free_command(GFP_KERNEL, scmd);
return rval;
}
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,
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_BIT_MASK(64));
adapter->has_64bit_addr = 1;
} else {
- pci_set_dma_mask(pdev, 0xffffffff);
+ pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
adapter->has_64bit_addr = 0;
}
- init_MUTEX(&adapter->int_mtx);
+ mutex_init(&adapter->int_mtx);
init_completion(&adapter->int_waitq);
adapter->this_id = DEFAULT_INITIATOR_ID;
mdelay(1000);
}
-static void
+static void __devexit
megaraid_remove_one(struct pci_dev *pdev)
{
struct Scsi_Host *host = pci_get_drvdata(pdev);
adapter_t *adapter = (adapter_t *)host->hostdata;
- char buf[12] = { 0 };
scsi_remove_host(host);
remove_proc_entry("raiddrives-30-39",
adapter->controller_proc_dir_entry);
#endif
- sprintf(buf, "hba%d", adapter->host->host_no);
- remove_proc_entry(buf, mega_proc_dir_entry);
+ {
+ char buf[12] = { 0 };
+ sprintf(buf, "hba%d", adapter->host->host_no);
+ remove_proc_entry(buf, mega_proc_dir_entry);
+ }
}
#endif
}
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),
max_mbox_busy_wait = MBOX_BUSY_WAIT;
#ifdef CONFIG_PROC_FS
- mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root);
+ mega_proc_dir_entry = proc_mkdir("megaraid", NULL);
if (!mega_proc_dir_entry) {
printk(KERN_WARNING
"megaraid: failed to create megaraid root\n");
}
#endif
- error = pci_module_init(&megaraid_pci_driver);
+ error = pci_register_driver(&megaraid_pci_driver);
if (error) {
#ifdef CONFIG_PROC_FS
- remove_proc_entry("megaraid", &proc_root);
+ remove_proc_entry("megaraid", NULL);
#endif
return error;
}
* 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);
+ remove_proc_entry("megaraid", NULL);
#endif
}