* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_mbox.c
- * Version : v2.20.4.6 (Mar 07 2005)
+ * Version : v2.20.4.9 (Jul 16 2006)
*
* Authors:
* Atul Mukker <Atul.Mukker@lsil.com>
* Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
* Manoj Jose <Manoj.Jose@lsil.com>
+ * Seokmann Ju <Seokmann.Ju@lsil.com>
*
* List of supported controllers
*
-MODULE_AUTHOR("LSI Logic Corporation");
+MODULE_AUTHOR("sju@lsil.com");
MODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGARAID_VERSION);
{
PCI_VENDOR_ID_AMI,
PCI_DEVICE_ID_AMI_MEGARAID3,
- PCI_VENDOR_ID_DELL,
- PCI_SUBSYS_ID_PERC3_QC,
- },
- {
- PCI_VENDOR_ID_AMI,
- PCI_DEVICE_ID_AMI_MEGARAID3,
- PCI_VENDOR_ID_DELL,
- PCI_SUBSYS_ID_PERC3_DC,
- },
- {
- PCI_VENDOR_ID_AMI,
- PCI_DEVICE_ID_AMI_MEGARAID3,
- PCI_VENDOR_ID_DELL,
- PCI_SUBSYS_ID_PERC3_SC,
- },
- {
- PCI_VENDOR_ID_AMI,
- PCI_DEVICE_ID_AMI_MEGARAID3,
- PCI_VENDOR_ID_AMI,
- PCI_SUBSYS_ID_PERC3_SC,
- },
- {
- PCI_VENDOR_ID_AMI,
- PCI_DEVICE_ID_AMI_MEGARAID3,
- PCI_VENDOR_ID_AMI,
- PCI_SUBSYS_ID_PERC3_DC,
- },
- {
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_MEGARAID_SCSI_320_0,
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_SUBSYS_ID_MEGARAID_SCSI_320_0,
- },
- {
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_MEGARAID_SCSI_320_1,
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_SUBSYS_ID_MEGARAID_SCSI_320_1,
- },
- {
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_MEGARAID_SCSI_320_2,
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_SUBSYS_ID_MEGARAID_SCSI_320_2,
- },
- {
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_MEGARAID_I4_133_RAID,
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_SUBSYS_ID_MEGARAID_I4_133_RAID,
- },
- {
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_MEGARAID_SATA_150_4,
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_SUBSYS_ID_MEGARAID_SATA_150_4,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_MEGARAID_SATA_150_6,
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_SUBSYS_ID_MEGARAID_SATA_150_6,
+ PCI_DEVICE_ID_AMI_MEGARAID3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_ANY_ID,
PCI_ANY_ID,
},
- {
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_INTEL_RAID_SRCS16,
- PCI_VENDOR_ID_INTEL,
- PCI_SUBSYS_ID_INTEL_RAID_SRCS16,
- },
- {
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK,
- PCI_VENDOR_ID_INTEL,
- PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK,
- },
{0} /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, pci_id_table_g);
// Initialize the synchronization lock for kernel and LLD
spin_lock_init(&adapter->lock);
- adapter->host_lock = &adapter->lock;
-
// Initialize the command queues: the list of free SCBs and the list
// of pending SCBs.
SCSIHOST2ADAP(host) = (caddr_t)adapter;
adapter->host = host;
- // export the parameters required by the mid-layer
- scsi_assign_lock(host, adapter->host_lock);
-
host->irq = adapter->irq;
host->unique_id = adapter->unique_id;
host->can_queue = adapter->max_cmds;
* . Allocate memory required for all the commands
* . Use internal library of FW routines, build up complete soft state
*/
-static int __init
+static int __devinit
megaraid_init_mbox(adapter_t *adapter)
{
struct pci_dev *pdev;
mraid_device_t *raid_dev;
int i;
+ uint32_t magic64;
adapter->ito = MBOX_TIMEOUT;
//
// request IRQ and register the interrupt service routine
- if (request_irq(adapter->irq, megaraid_isr, SA_SHIRQ, "megaraid",
+ if (request_irq(adapter->irq, megaraid_isr, IRQF_SHARED, "megaraid",
adapter)) {
con_log(CL_ANN, (KERN_WARNING
// Set the DMA mask to 64-bit. All supported controllers as capable of
// DMA in this range
- if (pci_set_dma_mask(adapter->pdev, DMA_64BIT_MASK) != 0) {
-
- con_log(CL_ANN, (KERN_WARNING
- "megaraid: could not set DMA mask for 64-bit.\n"));
+ pci_read_config_dword(adapter->pdev, PCI_CONF_AMISIG64, &magic64);
+
+ if (((magic64 == HBA_SIGNATURE_64_BIT) &&
+ ((adapter->pdev->subsystem_device !=
+ PCI_SUBSYS_ID_MEGARAID_SATA_150_6) ||
+ (adapter->pdev->subsystem_device !=
+ PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
+ adapter->pdev->device == PCI_DEVICE_ID_VERDE) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
+ adapter->pdev->device == PCI_DEVICE_ID_DOBSON) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
+ adapter->pdev->device == PCI_DEVICE_ID_LINDSAY) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_DELL &&
+ adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_DELL &&
+ adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) {
+ if (pci_set_dma_mask(adapter->pdev, DMA_64BIT_MASK)) {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: DMA mask for 64-bit failed\n"));
- goto out_free_sysfs_res;
+ if (pci_set_dma_mask (adapter->pdev, DMA_32BIT_MASK)) {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: 32-bit DMA mask failed\n"));
+ goto out_free_sysfs_res;
+ }
+ }
}
// setup tasklet for DPC
* return the scb from the head of the free list. NULL if there are none
* available
**/
-static inline scb_t *
+static scb_t *
megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp)
{
struct list_head *head = &adapter->kscb_pool;
*
* prepare the scatter-gather list
*/
-static inline int
+static int
megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
{
struct scatterlist *sgl;
*
* post the command to the controller if mailbox is availble.
*/
-static inline int
+static int
mbox_post_cmd(adapter_t *adapter, scb_t *scb)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
scp->scsi_done = done;
scp->result = 0;
- assert_spin_locked(adapter->host_lock);
-
- spin_unlock(adapter->host_lock);
-
/*
* Allocate and build a SCB request
* if_busy flag will be set if megaraid_mbox_build_cmd() command could
* return 0 in that case, and we would do the callback right away.
*/
if_busy = 0;
- scb = megaraid_mbox_build_cmd(adapter, scp, &if_busy);
-
- if (scb) {
- megaraid_mbox_runpendq(adapter, scb);
- }
-
- spin_lock(adapter->host_lock);
-
+ scb = megaraid_mbox_build_cmd(adapter, scp, &if_busy);
if (!scb) { // command already completed
done(scp);
return 0;
}
+ megaraid_mbox_runpendq(adapter, scb);
return if_busy;
}
-
/**
* megaraid_mbox_build_cmd - transform the mid-layer scsi command to megaraid
* firmware lingua
rdev->last_disp |= (1L << SCP2CHANNEL(scp));
}
+ if (scp->cmnd[1] & MEGA_SCSI_INQ_EVPD) {
+ scp->sense_buffer[0] = 0x70;
+ scp->sense_buffer[2] = ILLEGAL_REQUEST;
+ scp->sense_buffer[12] = MEGA_INVALID_FIELD_IN_CDB;
+ scp->result = CHECK_CONDITION << 1;
+ return NULL;
+ }
+
/* Fall through */
case READ_CAPACITY:
*
* Returns: 1 if the interrupt is valid, 0 otherwise
*/
-static inline int
+static int
megaraid_ack_sequence(adapter_t *adapter)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
*
* DMA sync if required.
*/
-static inline void
+static void
megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb)
{
mbox_ccb_t *ccb;
unsigned long flags;
uint8_t c;
int status;
+ uioc_t *kioc;
if (!adapter) return;
// remove from local clist
list_del_init(&scb->list);
+ kioc = (uioc_t *)scb->gp;
+ kioc->status = 0;
+
megaraid_mbox_mm_done(adapter, scb);
continue;
megaraid_dealloc_scb(adapter, scb);
// send the scsi packet back to kernel
- spin_lock(adapter->host_lock);
scp->scsi_done(scp);
- spin_unlock(adapter->host_lock);
}
return;
* aborted. All the commands issued to the F/W must complete.
**/
static int
-__megaraid_abort_handler(struct scsi_cmnd *scp)
+megaraid_abort_handler(struct scsi_cmnd *scp)
{
adapter_t *adapter;
mraid_device_t *raid_dev;
adapter = SCP2ADAPTER(scp);
raid_dev = ADAP2RAIDDEV(adapter);
- assert_spin_locked(adapter->host_lock);
-
con_log(CL_ANN, (KERN_WARNING
"megaraid: aborting-%ld cmd=%x <c=%d t=%d l=%d>\n",
scp->serial_number, scp->cmnd[0], SCP2CHANNEL(scp),
// traverse through the list of all SCB, since driver does not
// maintain these SCBs on any list
found = 0;
+ spin_lock_irq(&adapter->lock);
for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
scb = adapter->kscb_list + i;
}
}
}
+ spin_unlock_irq(&adapter->lock);
if (!found) {
con_log(CL_ANN, (KERN_WARNING
return FAILED;
}
-static int
-megaraid_abort_handler(struct scsi_cmnd *scp)
-{
- adapter_t *adapter;
- int rc;
-
- adapter = SCP2ADAPTER(scp);
-
- spin_lock_irq(adapter->host_lock);
- rc = __megaraid_abort_handler(scp);
- spin_unlock_irq(adapter->host_lock);
-
- return rc;
-}
-
-
/**
* megaraid_reset_handler - device reset hadler for mailbox based driver
* @scp : reference command
* host
**/
static int
-__megaraid_reset_handler(struct scsi_cmnd *scp)
+megaraid_reset_handler(struct scsi_cmnd *scp)
{
adapter_t *adapter;
scb_t *scb;
int recovery_window;
int recovering;
int i;
+ uioc_t *kioc;
adapter = SCP2ADAPTER(scp);
raid_dev = ADAP2RAIDDEV(adapter);
- assert_spin_locked(adapter->host_lock);
-
- con_log(CL_ANN, (KERN_WARNING "megaraid: reseting the host...\n"));
-
// return failure if adapter is not responding
if (raid_dev->hw_error) {
con_log(CL_ANN, (KERN_NOTICE
// Also, reset all the commands currently owned by the driver
spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) {
-
list_del_init(&scb->list); // from pending list
- con_log(CL_ANN, (KERN_WARNING
- "megaraid: %ld:%d[%d:%d], reset from pending list\n",
- scp->serial_number, scb->sno,
- scb->dev_channel, scb->dev_target));
+ if (scb->sno >= MBOX_MAX_SCSI_CMDS) {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: IOCTL packet with %d[%d:%d] being reset\n",
+ scb->sno, scb->dev_channel, scb->dev_target));
- scp->result = (DID_RESET << 16);
- scp->scsi_done(scp);
+ scb->status = -1;
- megaraid_dealloc_scb(adapter, scb);
+ kioc = (uioc_t *)scb->gp;
+ kioc->status = -EFAULT;
+
+ megaraid_mbox_mm_done(adapter, scb);
+ } else {
+ if (scb->scp == scp) { // Found command
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: %ld:%d[%d:%d], reset from pending list\n",
+ scp->serial_number, scb->sno,
+ scb->dev_channel, scb->dev_target));
+ } else {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: IO packet with %d[%d:%d] being reset\n",
+ scb->sno, scb->dev_channel, scb->dev_target));
+ }
+
+ scb->scp->result = (DID_RESET << 16);
+ scb->scp->scsi_done(scb->scp);
+
+ megaraid_dealloc_scb(adapter, scb);
+ }
}
spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
if (adapter->outstanding_cmds) {
con_log(CL_ANN, (KERN_NOTICE
"megaraid: %d outstanding commands. Max wait %d sec\n",
- adapter->outstanding_cmds, MBOX_RESET_WAIT));
+ adapter->outstanding_cmds,
+ (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT)));
}
- spin_unlock(adapter->host_lock);
-
recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT;
recovering = adapter->outstanding_cmds;
- for (i = 0; i < recovery_window && adapter->outstanding_cmds; i++) {
+ for (i = 0; i < recovery_window; i++) {
megaraid_ack_sequence(adapter);
con_log(CL_ANN, (
"megaraid mbox: Wait for %d commands to complete:%d\n",
adapter->outstanding_cmds,
- MBOX_RESET_WAIT - i));
+ (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT) - i));
}
// bailout if no recovery happended in reset time
- if ((i == MBOX_RESET_WAIT) &&
- (recovering == adapter->outstanding_cmds)) {
+ if (adapter->outstanding_cmds == 0) {
break;
}
msleep(1000);
}
- spin_lock(adapter->host_lock);
+ spin_lock(&adapter->lock);
// If still outstanding commands, bail out
if (adapter->outstanding_cmds) {
raid_dev->hw_error = 1;
- return FAILED;
+ rval = FAILED;
+ goto out;
}
else {
con_log(CL_ANN, (KERN_NOTICE
// If the controller supports clustering, reset reservations
- if (!adapter->ha) return SUCCESS;
+ if (!adapter->ha) {
+ rval = SUCCESS;
+ goto out;
+ }
// clear reservations if any
raw_mbox[0] = CLUSTER_CMD;
"megaraid: reservation reset failed\n"));
}
+ out:
+ spin_unlock_irq(&adapter->lock);
return rval;
}
-static int
-megaraid_reset_handler(struct scsi_cmnd *cmd)
-{
- int rc;
-
- spin_lock_irq(cmd->device->host->host_lock);
- rc = __megaraid_reset_handler(cmd);
- spin_unlock_irq(cmd->device->host->host_lock);
-
- return rc;
-}
-
-
/*
* START: internal commands library
*
// available within 1 second, assume FW is initializing and wait
// for an extended amount of time
if (mbox->numstatus == 0xFF) { // status not yet available
- udelay(25);;
+ udelay(25);
for (i = 0; mbox->numstatus == 0xFF && i < 1000; i++) {
rmb();
wmb();
WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
- for (i = 0; i < 0xFFFFF; i++) {
+ for (i = 0; i < MBOX_SYNC_WAIT_CNT; i++) {
if (mbox->numstatus != 0xFF) break;
+ rmb();
+ udelay(MBOX_SYNC_DELAY_200);
}
- if (i == 0xFFFFF) {
+ if (i == MBOX_SYNC_WAIT_CNT) {
// We may need to re-calibrate the counter
con_log(CL_ANN, (KERN_CRIT
"megaraid: fast sync command timed out\n"));
adp.drvr_data = (unsigned long)adapter;
adp.pdev = adapter->pdev;
adp.issue_uioc = megaraid_mbox_mm_handler;
- adp.timeout = 300;
+ adp.timeout = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT;
adp.max_kioc = MBOX_MAX_USER_CMDS;
if ((rval = mraid_mm_register_adp(&adp)) != 0) {
/*
* Set the quiescent flag to stop issuing cmds to FW.
*/
- spin_lock_irqsave(adapter->host_lock, flags);
+ spin_lock_irqsave(&adapter->lock, flags);
adapter->quiescent++;
- spin_unlock_irqrestore(adapter->host_lock, flags);
+ spin_unlock_irqrestore(&adapter->lock, flags);
/*
* Wait till there are no more cmds outstanding at FW. Try for at most
unsigned long flags;
kioc = (uioc_t *)scb->gp;
- kioc->status = 0;
mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf;
mbox64->mbox32.status = scb->status;
raw_mbox = (uint8_t *)&mbox64->mbox32;