Commit 9cd56c73 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by James Bottomley

[PATCH] convert inia100 to new probing API

Hi Doug,

you've been the last who touched inia100.c, so I may assume you
actually have the hardware?  I've updated the driver to the new
pci probing and scsi host registration code and it would be cool
if someone could test it so we could merge it into early 2.6.
parent 652490f0
......@@ -108,9 +108,6 @@ ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);
/* ---- EXTERNAL FUNCTIONS ---- */
extern void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
/* ---- INTERNAL VARIABLES ---- */
struct inia100_Adpt_Struc *inia100_adpt;
NVRAM nvram, *nvramp = &nvram;
static UCHAR dftNvRam[64] =
{
......@@ -702,83 +699,6 @@ void orc_release_dma(ORC_HCS * hcsp, Scsi_Cmnd * SCpnt)
}
}
/*****************************************************************************
Function name : Addinia100_into_Adapter_table
Description : This function will scan PCI bus to get all Orchid card
Input : None.
Output : None.
Return : SUCCESSFUL - Successful scan
ohterwise - No drives founded
*****************************************************************************/
int Addinia100_into_Adapter_table(WORD wBIOS, WORD wBASE, struct pci_dev *pdev,
int iAdapters)
{
unsigned int i, j;
for (i = 0; i < iAdapters; i++) {
if (inia100_adpt[i].ADPT_BIOS < wBIOS)
continue;
if (inia100_adpt[i].ADPT_BIOS == wBIOS) {
if (inia100_adpt[i].ADPT_BASE == wBASE) {
if (inia100_adpt[i].ADPT_pdev->bus->number != 0xFF)
return (FAILURE);
} else if (inia100_adpt[i].ADPT_BASE < wBASE)
continue;
}
for (j = iAdapters - 1; j > i; j--) {
inia100_adpt[j].ADPT_BASE = inia100_adpt[j - 1].ADPT_BASE;
inia100_adpt[j].ADPT_BIOS = inia100_adpt[j - 1].ADPT_BIOS;
inia100_adpt[j].ADPT_pdev = inia100_adpt[j - 1].ADPT_pdev;
}
inia100_adpt[i].ADPT_BASE = wBASE;
inia100_adpt[i].ADPT_BIOS = wBIOS;
inia100_adpt[i].ADPT_pdev = pdev;
return (SUCCESSFUL);
}
return (FAILURE);
}
/*****************************************************************************
Function name : init_inia100Adapter_table
Description : This function will scan PCI bus to get all Orchid card
Input : None.
Output : None.
Return : 0 on success, 1 on failure
*****************************************************************************/
int init_inia100Adapter_table(int iAdapters)
{
int i;
inia100_adpt = kmalloc(sizeof(INIA100_ADPT_STRUCT) * iAdapters,
GFP_KERNEL);
if(inia100_adpt == NULL)
return 1;
for (i = 0; i < iAdapters; i++) {/* Initialize adapter structure */
inia100_adpt[i].ADPT_BIOS = 0xffff;
inia100_adpt[i].ADPT_BASE = 0xffff;
inia100_adpt[i].ADPT_pdev = NULL;
}
return 0;
}
/*****************************************************************************
Function name : get_orcPCIConfig
Description :
Input : pHCB - Pointer to host adapter structure
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx)
{
pCurHcb->HCS_Base = inia100_adpt[ch_idx].ADPT_BASE; /* Supply base address */
pCurHcb->HCS_BIOS = inia100_adpt[ch_idx].ADPT_BIOS; /* Supply BIOS address */
pCurHcb->HCS_Intr = inia100_adpt[ch_idx].ADPT_pdev->irq; /* Supply interrupt line */
return;
}
/*****************************************************************************
Function name : abort_SCB
Description : Abort a queued command.
......
......@@ -65,10 +65,15 @@
* - Clean up interrupt handler registration
* - Fix memory leaks
* - Fix allocation of scsi host structs and private data
* 18/11/03 Christoph Hellwig <hch@lst.de>
* - Port to new probing API
* - Fix some more leaks in init failure cases
* TODO:
* - use list.h macros for SCB queue
* ( - merge with i60uscsi.c )
**************************************************************************/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
......@@ -76,37 +81,19 @@
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
//#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <asm/io.h>
#include <asm/irq.h>
#include "scsi.h"
#include "hosts.h"
#include "inia100.h"
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
static Scsi_Host_Template driver_template = {
.proc_name = "inia100",
.name = inia100_REVID,
.detect = inia100_detect,
.release = inia100_release,
.queuecommand = inia100_queue,
.eh_abort_handler = inia100_abort,
.eh_bus_reset_handler = inia100_bus_reset,
.eh_device_reset_handler = inia100_device_reset,
.can_queue = 1,
.this_id = 1,
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
};
#include "scsi_module.c"
#include "inia100.h"
#define ORC_RDWORD(x,y) (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
......@@ -115,32 +102,19 @@ char *inia100_InitioName = "by Initio Corporation";
char *inia100_ProductName = "INI-A100U2W";
char *inia100_Version = "v1.02d";
/* set by inia100_setup according to the command line */
static int setup_called = 0;
/* ---- INTERNAL VARIABLES ---- */
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
static char *setup_str = (char *) NULL;
static irqreturn_t inia100_intr(int, void *, struct pt_regs *);
static void inia100_panic(char *msg);
/* ---- EXTERNAL FUNCTIONS ---- */
extern void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
extern int Addinia100_into_Adapter_table(WORD, WORD, struct pci_dev *, int);
extern int init_inia100Adapter_table(int);
extern ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);
extern void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp);
extern void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp);
extern void orc_release_dma(ORC_HCS * hcsp, Scsi_Cmnd * cmnd);
extern void orc_release_dma(ORC_HCS * hcsp, struct scsi_cmnd * cmnd);
extern void orc_interrupt(ORC_HCS * hcsp);
extern int orc_device_reset(ORC_HCS * pHCB, Scsi_Cmnd *SCpnt, unsigned int target);
extern int orc_device_reset(ORC_HCS * pHCB, struct scsi_cmnd *SCpnt, unsigned int target);
extern int orc_reset_scsi_bus(ORC_HCS * pHCB);
extern int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb);
extern int orc_abort_srb(ORC_HCS * hcsp, Scsi_Cmnd *SCpnt);
extern void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx);
extern int orc_abort_srb(ORC_HCS * hcsp, struct scsi_cmnd *SCpnt);
extern int init_orchid(ORC_HCS * hcsp);
extern struct inia100_Adpt_Struc *inia100_adpt;
/*****************************************************************************
Function name : inia100AppendSRBToQueue
......@@ -150,7 +124,7 @@ extern struct inia100_Adpt_Struc *inia100_adpt;
Output : None.
Return : None.
*****************************************************************************/
static void inia100AppendSRBToQueue(ORC_HCS * pHCB, Scsi_Cmnd * pSRB)
static void inia100AppendSRBToQueue(ORC_HCS * pHCB, struct scsi_cmnd * pSRB)
{
ULONG flags;
......@@ -173,279 +147,19 @@ static void inia100AppendSRBToQueue(ORC_HCS * pHCB, Scsi_Cmnd * pSRB)
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
static Scsi_Cmnd *inia100PopSRBFromQueue(ORC_HCS * pHCB)
static struct scsi_cmnd *inia100PopSRBFromQueue(ORC_HCS * pHCB)
{
Scsi_Cmnd *pSRB;
struct scsi_cmnd *pSRB;
ULONG flags;
spin_lock_irqsave(&(pHCB->pSRB_lock), flags);
if ((pSRB = (Scsi_Cmnd *) pHCB->pSRB_head) != NULL) {
pHCB->pSRB_head = (Scsi_Cmnd *) pHCB->pSRB_head->SCp.ptr;
if ((pSRB = (struct scsi_cmnd *) pHCB->pSRB_head) != NULL) {
pHCB->pSRB_head = (struct scsi_cmnd *) pHCB->pSRB_head->SCp.ptr;
pSRB->SCp.ptr = NULL;
}
spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags);
return (pSRB);
}
/*****************************************************************************
Function name : inia100_setup
Description :
Input : pHCB - Pointer to host adapter structure
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
void inia100_setup(char *str, int *ints)
{
if (setup_called)
inia100_panic("inia100: inia100_setup called twice.\n");
setup_called = ints[0];
setup_str = str;
}
/*****************************************************************************
Function name : orc_ReturnNumberOfAdapters
Description : This function will scan PCI bus to get all Orchid card
Input : None.
Output : None.
Return : SUCCESSFUL - Successful scan
ohterwise - No drives founded
*****************************************************************************/
int orc_ReturnNumberOfAdapters(void)
{
unsigned int iAdapters;
iAdapters = 0;
/*
* PCI-bus probe.
*/
{
/*
* Note: I removed the struct pci_device_list stuff since this
* driver only cares about one device ID. If that changes in
* the future it can be added in with only a very moderate
* amount of work. It made the double scan of the device list
* for getting a count and allocating the device list easier
* to not have the for(i ... ) loop in there....
*/
unsigned int dRegValue;
WORD wBIOS, wBASE;
#ifdef MMAPIO
unsigned long page_offset, base;
#endif
struct pci_dev *pdev = NULL;
/*
* Get a count of adapters that we expect to be able to use.
* Pass that count to init_inia100Adapter_table() for malloc
* reasons.
*/
pdev = NULL;
while((pdev=pci_find_device(ORC_VENDOR_ID, ORC_DEVICE_ID, pdev)))
{
if (pci_enable_device(pdev))
continue;
if (pci_set_dma_mask(pdev, (u64)0xffffffff)) {
printk(KERN_WARNING "Unable to set 32bit DMA "
"on inia100 adapter, ignoring.\n");
continue;
}
iAdapters++;
}
if(init_inia100Adapter_table(iAdapters))
return 0;
/*
* Now go through the adapters again actually setting them up
* and putting them in the table this time.
*/
pdev = NULL;
while((pdev=pci_find_device(ORC_VENDOR_ID, ORC_DEVICE_ID, pdev)))
{
/*
* Read sundry information from PCI BIOS.
*/
dRegValue = pci_resource_start(pdev, 0);
if (dRegValue == -1) { /* Check return code */
printk("\n\rinia100: orchid read configuration error.\n");
iAdapters--;
continue; /* Read configuration space error */
}
/* <02> read from base address + 0x50 offset to get the wBIOS balue. */
wBASE = (WORD) dRegValue;
/* Now read the interrupt line value */
dRegValue = pdev->irq;
wBIOS = ORC_RDWORD(wBASE, 0x50);
pci_set_master(pdev);
#ifdef MMAPIO
base = wBASE & PAGE_MASK;
page_offset = wBASE - base;
/*
* replace the next line with this one if you are using 2.1.x:
* temp_p->maddr = ioremap(base, page_offset + 256);
*/
wBASE = ioremap(base, page_offset + 256);
if (wBASE) {
wBASE += page_offset;
}
#endif
Addinia100_into_Adapter_table(wBIOS, wBASE, pdev, iAdapters);
} /* while(pdev=....) */
} /* PCI BIOS present */
return (iAdapters);
}
/*****************************************************************************
Function name : inia100_detect
Description :
Input : pHCB - Pointer to host adapter structure
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
int inia100_detect(Scsi_Host_Template * tpnt)
{
ORC_HCS *pHCB;
struct Scsi_Host *hreg;
U32 sz;
U32 i; /* 01/14/98 */
int ok = 0, iAdapters;
ULONG dBiosAdr;
BYTE *pbBiosAdr;
struct pci_dev *pdev;
tpnt->proc_name = "inia100";
if (setup_called) {
/* Setup by inia100_setup */
printk("inia100: processing commandline: ");
}
/* Get total number of adapters in the motherboard */
iAdapters = orc_ReturnNumberOfAdapters();
/* printk("inia100: Total Initio Adapters = %d\n", iAdapters); */
if (iAdapters == 0) /* If no orc founded, return */
return (0);
#if 0
printk("orc_num_scb= %x orc_num_ch= %x hcsize= %x scbsize= %x escbsize= %x\n",
orc_num_scb, orc_num_ch, sizeof(ORC_HCS), sizeof(ORC_SCB), sizeof(ESCB));
#endif
for (i = 0; i < iAdapters; i++) {
pdev = inia100_adpt[i].ADPT_pdev;
hreg = scsi_register(tpnt, sizeof(ORC_HCS));
if (hreg == NULL) {
goto out_disable;
}
pHCB = (ORC_HCS *)hreg->hostdata;
pHCB->pdev = pdev;
pHCB->pSRB_head = NULL; /* Initial SRB save queue */
pHCB->pSRB_tail = NULL; /* Initial SRB save queue */
pHCB->pSRB_lock = SPIN_LOCK_UNLOCKED; /* SRB save queue lock */
pHCB->BitAllocFlagLock = SPIN_LOCK_UNLOCKED;
/* Get total memory needed for SCB */
sz = ORC_MAXQUEUE * sizeof(ORC_SCB);
if ((pHCB->HCS_virScbArray = (PVOID) pci_alloc_consistent(pdev, sz, &pHCB->HCS_physScbArray)) == NULL) {
printk("inia100: SCB memory allocation error\n");
goto out_unregister;
}
memset((unsigned char *) pHCB->HCS_virScbArray, 0, sz);
/* Get total memory needed for ESCB */
sz = ORC_MAXQUEUE * sizeof(ESCB);
if ((pHCB->HCS_virEscbArray = (PVOID) pci_alloc_consistent(pdev, sz, &pHCB->HCS_physEscbArray)) == NULL) {
printk("inia100: ESCB memory allocation error\n");
goto out_unalloc;
}
memset((unsigned char *) pHCB->HCS_virEscbArray, 0, sz);
get_orcPCIConfig(pHCB, i);
dBiosAdr = pHCB->HCS_BIOS;
dBiosAdr = (dBiosAdr << 4);
pbBiosAdr = phys_to_virt(dBiosAdr);
if (init_orchid(pHCB)) { /* Initial orchid chip */
printk("inia100: initial orchid fail!!\n");
goto out_unalloc;
}
if (!request_region(pHCB->HCS_Base, 256, "inia100")) {
printk(KERN_WARNING "inia100: io port 0x%x, is busy.\n",
pHCB->HCS_Base);
return (0);
}
hreg->io_port = pHCB->HCS_Base;
hreg->n_io_port = 0xff;
hreg->can_queue = ORC_MAXQUEUE; /* 03/05/98 */
hreg->unique_id = pHCB->HCS_Base;
hreg->max_id = pHCB->HCS_MaxTar;
hreg->max_lun = 16; /* 10/21/97 */
/*
hreg->max_lun = 8;
hreg->max_channel = 1;
*/
hreg->irq = pHCB->HCS_Intr;
hreg->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */
#if 1
hreg->sg_tablesize = TOTAL_SG_ENTRY; /* Maximun support is 32 */
#else
hreg->sg_tablesize = SG_NONE; /* No SG */
#endif
/* Initial orc chip */
ok = request_irq(pHCB->HCS_Intr, inia100_intr, SA_SHIRQ, "inia100", hreg);
if (ok < 0) {
if (ok == -EINVAL) {
printk("inia100: bad IRQ %d.\n", pHCB->HCS_Intr);
printk(" Contact author.\n");
} else {
if (ok == -EBUSY)
printk("inia100: IRQ %d already in use. Configure another.\n", pHCB->HCS_Intr);
else {
printk("\ninia100: Unexpected error code on requesting IRQ %d.\n",
pHCB->HCS_Intr);
printk(" Contact author.\n");
}
}
goto out_irq;
}
}
tpnt->this_id = -1;
tpnt->can_queue = 1;
kfree(inia100_adpt);
return 1;
out_irq:
release_region(pHCB->HCS_Base, 256);
out_unalloc:
if(pHCB->HCS_virEscbArray) {
pci_free_consistent(pHCB->pdev, ORC_MAXQUEUE * sizeof(ESCB),
pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
pHCB->HCS_virEscbArray = NULL;
}
if(pHCB->HCS_virScbArray) {
pci_free_consistent(pHCB->pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
pHCB->HCS_virScbArray = NULL;
}
out_unregister:
scsi_unregister(hreg);
out_disable:
pci_disable_device(pdev);
kfree(inia100_adpt);
return i;
}
/*****************************************************************************
Function name : inia100BuildSCB
Description :
......@@ -453,7 +167,7 @@ int inia100_detect(Scsi_Host_Template * tpnt)
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, Scsi_Cmnd * SCpnt)
static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, struct scsi_cmnd * SCpnt)
{ /* Create corresponding SCB */
struct scatterlist *pSrbSG;
ORC_SG *pSG; /* Pointer to SG list */
......@@ -479,7 +193,7 @@ static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, Scsi_Cmnd * SCpnt)
TotalLen = 0;
pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
count_sg = pci_map_sg(pHCB->pdev, pSrbSG, SCpnt->use_sg,
scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
SCpnt->sc_data_direction);
pSCB->SCB_SGLen = (U32) (count_sg * 8);
for (i = 0; i < count_sg; i++, pSG++, pSrbSG++) {
pSG->SG_Ptr = (U32) sg_dma_address(pSrbSG);
......@@ -490,7 +204,7 @@ static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, Scsi_Cmnd * SCpnt)
pSCB->SCB_SGLen = 0x8;
pSG->SG_Ptr = (U32) pci_map_single(pHCB->pdev,
SCpnt->request_buffer, SCpnt->request_bufflen,
scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
SCpnt->sc_data_direction);
SCpnt->host_scribble = (void *)pSG->SG_Ptr;
pSG->SG_Len = (U32) SCpnt->request_bufflen;
} else {
......@@ -526,7 +240,7 @@ static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, Scsi_Cmnd * SCpnt)
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
static int inia100_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
static int inia100_queue(struct scsi_cmnd * SCpnt, void (*done) (struct scsi_cmnd *))
{
register ORC_SCB *pSCB;
ORC_HCS *pHCB; /* Point to Host adapter control block */
......@@ -553,7 +267,7 @@ static int inia100_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
static int inia100_abort(Scsi_Cmnd * SCpnt)
static int inia100_abort(struct scsi_cmnd * SCpnt)
{
ORC_HCS *hcsp;
......@@ -569,7 +283,7 @@ static int inia100_abort(Scsi_Cmnd * SCpnt)
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
static int inia100_bus_reset(Scsi_Cmnd * SCpnt)
static int inia100_bus_reset(struct scsi_cmnd * SCpnt)
{ /* I need Host Control Block Information */
ORC_HCS *pHCB;
pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
......@@ -583,7 +297,7 @@ static int inia100_bus_reset(Scsi_Cmnd * SCpnt)
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
static int inia100_device_reset(Scsi_Cmnd * SCpnt)
static int inia100_device_reset(struct scsi_cmnd * SCpnt)
{ /* I need Host Control Block Information */
ORC_HCS *pHCB;
pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
......@@ -602,7 +316,7 @@ static int inia100_device_reset(Scsi_Cmnd * SCpnt)
*****************************************************************************/
void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
{
Scsi_Cmnd *pSRB; /* Pointer to SCSI request block */
struct scsi_cmnd *pSRB; /* Pointer to SCSI request block */
ORC_HCS *pHCB;
ORC_SCB *pSCB;
ESCB *pEScb;
......@@ -610,7 +324,7 @@ void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
pHCB = (ORC_HCS *) pHcb;
pSCB = (ORC_SCB *) pScb;
pEScb = pSCB->SCB_EScb;
if ((pSRB = (Scsi_Cmnd *) pEScb->SCB_Srb) == 0) {
if ((pSRB = (struct scsi_cmnd *) pEScb->SCB_Srb) == 0) {
printk("inia100SCBPost: SRB pointer is empty\n");
orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */
return;
......@@ -676,47 +390,187 @@ void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
static irqreturn_t inia100_intr(int irqno, void *devid, struct pt_regs *regs)
{
struct Scsi_Host *host = (struct Scsi_Host *)devid;
ORC_HCS *pHcb;
ORC_HCS *pHcb = (ORC_HCS *)host->hostdata;
unsigned long flags;
pHcb = (ORC_HCS *)host->hostdata; /* Host adapter control block */
spin_lock_irqsave(host->host_lock, flags);
orc_interrupt(pHcb);
spin_unlock_irqrestore(host->host_lock, flags);
return IRQ_HANDLED;
}
/*
* Dump the current driver status and panic...
*/
static void inia100_panic(char *msg)
static struct scsi_host_template inia100_template = {
.proc_name = "inia100",
.name = inia100_REVID,
.queuecommand = inia100_queue,
.eh_abort_handler = inia100_abort,
.eh_bus_reset_handler = inia100_bus_reset,
.eh_device_reset_handler = inia100_device_reset,
.can_queue = 1,
.this_id = 1,
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
};
static int __devinit inia100_probe_one(struct pci_dev *pdev,
const struct pci_device_id *id)
{
printk("\ninia100_panic: %s\n", msg);
panic("inia100 panic");
struct Scsi_Host *shost;
ORC_HCS *pHCB;
unsigned long port, bios;
int ok = -ENODEV;
u32 sz;
unsigned long dBiosAdr;
char *pbBiosAdr;
if (pci_enable_device(pdev))
goto out;
if (pci_set_dma_mask(pdev, 0xffffffffULL)) {
printk(KERN_WARNING "Unable to set 32bit DMA "
"on inia100 adapter, ignoring.\n");
goto out_disable_device;
}
port = pci_resource_start(pdev, 0);
if (!request_region(pHCB->HCS_Base, 256, "inia100")) {
printk(KERN_WARNING "inia100: io port 0x%x, is busy.\n",
pHCB->HCS_Base);
goto out_disable_device; /* XXX: undo init_orchid() ?? */
}
/* <02> read from base address + 0x50 offset to get the bios balue. */
bios = ORC_RDWORD(port, 0x50);
pci_set_master(pdev);
shost = scsi_host_alloc(&inia100_template, sizeof(ORC_HCS));
if (!shost)
goto out_release_region;
pHCB = (ORC_HCS *)shost->hostdata;
pHCB->pdev = pdev;
pHCB->HCS_Base = port;
pHCB->HCS_BIOS = bios;
pHCB->pSRB_head = NULL; /* Initial SRB save queue */
pHCB->pSRB_tail = NULL; /* Initial SRB save queue */
pHCB->pSRB_lock = SPIN_LOCK_UNLOCKED; /* SRB save queue lock */
pHCB->BitAllocFlagLock = SPIN_LOCK_UNLOCKED;
/* Get total memory needed for SCB */
sz = ORC_MAXQUEUE * sizeof(ORC_SCB);
pHCB->HCS_virScbArray = pci_alloc_consistent(pdev, sz, &pHCB->HCS_physScbArray);
if (!pHCB->HCS_virScbArray) {
printk("inia100: SCB memory allocation error\n");
goto out_host_put;
}
memset(pHCB->HCS_virScbArray, 0, sz);
/* Get total memory needed for ESCB */
sz = ORC_MAXQUEUE * sizeof(ESCB);
pHCB->HCS_virEscbArray = pci_alloc_consistent(pdev, sz, &pHCB->HCS_physEscbArray);
if (!pHCB->HCS_virEscbArray) {
printk("inia100: ESCB memory allocation error\n");
goto out_free_scb_array;
}
memset(pHCB->HCS_virEscbArray, 0, sz);
dBiosAdr = pHCB->HCS_BIOS;
dBiosAdr = (dBiosAdr << 4);
pbBiosAdr = phys_to_virt(dBiosAdr);
if (init_orchid(pHCB)) { /* Initialize orchid chip */
printk("inia100: initial orchid fail!!\n");
goto out_free_escb_array;
}
shost->io_port = pHCB->HCS_Base;
shost->n_io_port = 0xff;
shost->can_queue = ORC_MAXQUEUE;
shost->unique_id = shost->io_port;
shost->max_id = pHCB->HCS_MaxTar;
shost->max_lun = 16;
shost->irq = pHCB->HCS_Intr;
shost->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */
shost->sg_tablesize = TOTAL_SG_ENTRY;
/* Initial orc chip */
ok = request_irq(pHCB->HCS_Intr, inia100_intr, SA_SHIRQ, "inia100", shost);
if (ok < 0) {
printk(KERN_WARNING "inia100: unable to get irq %d\n", pHCB->HCS_Intr);
goto out_free_escb_array;
}
pci_set_drvdata(pdev, shost);
ok = scsi_add_host(shost, &pdev->dev);
if (!ok)
goto out_free_irq;
scsi_scan_host(shost);
return 0;
out_free_irq:
free_irq(shost->irq, shost);
out_free_escb_array:
pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB),
pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
out_free_scb_array:
pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
out_host_put:
scsi_host_put(shost);
out_release_region:
release_region(pHCB->HCS_Base, 256);
out_disable_device:
pci_disable_device(pdev);
out:
return ok;
}
/*
* Release ressources
*/
static int inia100_release(struct Scsi_Host *hreg)
static void __devexit inia100_remove_one(struct pci_dev *pdev)
{
ORC_HCS *pHCB = (ORC_HCS *)hreg->hostdata;
struct Scsi_Host *shost = pci_get_drvdata(pdev);
ORC_HCS *pHCB = (ORC_HCS *)shost->hostdata;
free_irq(hreg->irq, hreg);
release_region(hreg->io_port, 256);
if(pHCB->HCS_virEscbArray) {
pci_free_consistent(pHCB->pdev, ORC_MAXQUEUE * sizeof(ESCB),
scsi_remove_host(shost);
free_irq(shost->irq, shost);
pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB),
pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
pHCB->HCS_virEscbArray = NULL;
}
if(pHCB->HCS_virScbArray) {
pci_free_consistent(pHCB->pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
pHCB->HCS_virScbArray = NULL;
}
pci_disable_device(pHCB->pdev);
return 0;
release_region(shost->io_port, 256);
scsi_host_put(shost);
}
static struct pci_device_id inia100_pci_tbl[] = {
{ORC_VENDOR_ID, ORC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};
MODULE_DEVICE_TABLE(pci, inia100_pci_tbl);
static struct pci_driver inia100_pci_driver = {
.name = "inia100",
.id_table = inia100_pci_tbl,
.probe = inia100_probe_one,
.remove = __devexit_p(inia100_remove_one),
};
static int __init inia100_init(void)
{
return pci_module_init(&inia100_pci_driver);
}
static void __exit inia100_exit(void)
{
pci_unregister_driver(&inia100_pci_driver);
}
MODULE_DESCRIPTION("Initio A100U2W SCSI driver");
MODULE_AUTHOR("Initio Corporation");
MODULE_LICENSE("Dual BSD/GPL");
/*#include "inia100scsi.c" */
module_init(inia100_init);
module_exit(inia100_exit);
......@@ -67,13 +67,6 @@
#include <linux/types.h>
#include <linux/pci.h>
static int inia100_detect(Scsi_Host_Template *);
static int inia100_release(struct Scsi_Host *);
static int inia100_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
static int inia100_abort(Scsi_Cmnd *);
static int inia100_device_reset(Scsi_Cmnd *);
static int inia100_bus_reset(Scsi_Cmnd *);
#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02d"
#define ULONG unsigned long
......@@ -115,13 +108,6 @@ typedef struct ORC_SG_Struc {
U32 SG_Len; /* Data Length */
} ORC_SG;
typedef struct inia100_Adpt_Struc {
UWORD ADPT_BIOS; /* 0 */
UWORD ADPT_BASE; /* 1 */
struct pci_dev *ADPT_pdev; /* 2 */
} INIA100_ADPT_STRUCT;
/* SCSI related definition */
#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */
#define DISC_ALLOW 0xC0 /* Disconnect is allowed */
......@@ -211,7 +197,7 @@ typedef struct inia100_Adpt_Struc {
typedef struct orc_extended_scb { /* Extended SCB */
ORC_SG ESCB_SGList[TOTAL_SG_ENTRY]; /*0 Start of SG list */
Scsi_Cmnd *SCB_Srb; /*50 SRB Pointer */
struct scsi_cmnd *SCB_Srb; /*50 SRB Pointer */
} ESCB;
/***********************************************************************
......@@ -344,8 +330,8 @@ typedef struct ORC_Ha_Ctrl_Struc {
ORC_TCS HCS_Tcs[16]; /* 28 */
U32 BitAllocFlag[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */
spinlock_t BitAllocFlagLock;
Scsi_Cmnd *pSRB_head;
Scsi_Cmnd *pSRB_tail;
struct scsi_cmnd *pSRB_head;
struct scsi_cmnd *pSRB_tail;
spinlock_t pSRB_lock;
struct pci_dev *pdev;
} ORC_HCS;
......
......@@ -14,6 +14,9 @@
* - speed-ups (list handling fixes, issued_list, optimizations.)
* - lots of cleanups.
*
* 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>
*
* Description: Linux device driver for LSI Logic MegaRAID controller
......@@ -79,10 +82,6 @@ static int hba_count;
static adapter_t *hba_soft_state[MAX_CONTROLLERS];
static struct proc_dir_entry *mega_proc_dir_entry;
static struct notifier_block mega_notifier = {
.notifier_call = megaraid_reboot_notify
};
/* For controller re-ordering */
static struct mega_hbas mega_hbas[MAX_CONTROLLERS];
......@@ -116,1073 +115,531 @@ static int major;
*/
static int trace_level;
/*
* megaraid_validate_parms()
*
* Validate that any module parms passed in
* have proper values.
*/
static void
megaraid_validate_parms(void)
{
if( (max_cmd_per_lun <= 0) || (max_cmd_per_lun > MAX_CMD_PER_LUN) )
max_cmd_per_lun = MAX_CMD_PER_LUN;
if( max_mbox_busy_wait > MBOX_BUSY_WAIT )
max_mbox_busy_wait = MBOX_BUSY_WAIT;
}
/**
* megaraid_detect()
* @host_template - Our soft state maintained by mid-layer
*
* the detect entry point for the mid-layer.
* We scan the PCI bus for our controllers and start them.
* mega_setup_mailbox()
* @adapter - pointer to our soft state
*
* Note: PCI_DEVICE_ID_PERC4_DI below represents the PERC4/Di class of
* products. All of them share the same vendor id, device id, and subsystem
* vendor id but different subsystem ids. As of now, driver does not use the
* subsystem id.
* Allocates a 8 byte aligned memory for the handshake mailbox.
*/
static int
megaraid_detect(Scsi_Host_Template *host_template)
mega_setup_mailbox(adapter_t *adapter)
{
int i;
u16 dev_sw_table[] = { /* Table of all supported
vendor/device ids */
unsigned long align;
PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DISCOVERY,
PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_PERC4_DI,
PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_PERC4_QC_VERDE,
PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID,
PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID2,
PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID3,
PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_AMI_MEGARAID3,
PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_AMI_MEGARAID3 };
adapter->una_mbox64 = pci_alloc_consistent(adapter->dev,
sizeof(mbox64_t), &adapter->una_mbox64_dma);
if( !adapter->una_mbox64 ) return -1;
host_template->proc_name = "megaraid";
adapter->mbox = &adapter->una_mbox64->mbox;
printk(KERN_NOTICE "megaraid: " MEGARAID_VERSION);
adapter->mbox = (mbox_t *)((((unsigned long) adapter->mbox) + 15) &
(~0UL ^ 0xFUL));
megaraid_validate_parms();
adapter->mbox64 = (mbox64_t *)(((unsigned long)adapter->mbox) - 8);
memset(mega_hbas, 0, sizeof (mega_hbas));
align = ((void *)adapter->mbox) - ((void *)&adapter->una_mbox64->mbox);
hba_count = 0;
adapter->mbox_dma = adapter->una_mbox64_dma + 8 + align;
/*
* Scan PCI bus for our all devices.
* Register the mailbox if the controller is an io-mapped controller
*/
for( i = 0; i < sizeof(dev_sw_table)/sizeof(u16); i += 2 ) {
if( adapter->flag & BOARD_IOMAP ) {
mega_find_card(host_template, dev_sw_table[i],
dev_sw_table[i+1]);
}
outb_p(adapter->mbox_dma & 0xFF,
adapter->host->io_port + MBOX_PORT0);
if(hba_count) {
/*
* re-order hosts so that one with bootable logical drive
* comes first
*/
#ifdef CONFIG_PROC_FS
mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root);
outb_p((adapter->mbox_dma >> 8) & 0xFF,
adapter->host->io_port + MBOX_PORT1);
if(!mega_proc_dir_entry) {
printk(KERN_WARNING
"megaraid: failed to create megaraid root\n");
}
else {
for(i = 0; i < hba_count; i++) {
mega_create_proc_entry(i, mega_proc_dir_entry);
}
}
#endif
outb_p((adapter->mbox_dma >> 16) & 0xFF,
adapter->host->io_port + MBOX_PORT2);
/*
* Register the driver as a character device, for applications
* to access it for ioctls.
* First argument (major) to register_chrdev implies a dynamic
* major number allocation.
*/
major = register_chrdev(0, "megadev", &megadev_fops);
outb_p((adapter->mbox_dma >> 24) & 0xFF,
adapter->host->io_port + MBOX_PORT3);
/*
* Register the Shutdown Notification hook in kernel
*/
if(register_reboot_notifier(&mega_notifier)) {
printk(KERN_WARNING
"MegaRAID Shutdown routine not registered!!\n");
}
outb_p(ENABLE_MBOX_BYTE,
adapter->host->io_port + ENABLE_MBOX_REGION);
irq_ack(adapter);
irq_enable(adapter);
}
return hba_count;
return 0;
}
/**
* mega_find_card() - find and start this controller
* @host_template - Our soft state maintained by mid-layer
* @pci_vendor - pci vendor id for this controller
* @pci_device - pci device id for this controller
*
* Scans the PCI bus for this vendor and device id combination, setup the
* resources, and register ourselves as a SCSI HBA driver, and setup all
* parameters for our soft state.
/*
* mega_query_adapter()
* @adapter - pointer to our soft state
*
* This routine also checks for some buggy firmware and ajust the flags
* accordingly.
* Issue the adapter inquiry commands to the controller and find out
* information and parameter about the devices attached
*/
static void
mega_find_card(Scsi_Host_Template *host_template, u16 pci_vendor,
u16 pci_device)
static int
mega_query_adapter(adapter_t *adapter)
{
struct Scsi_Host *host = NULL;
adapter_t *adapter = NULL;
u32 magic64;
unsigned long mega_baseport;
u16 subsysid, subsysvid;
u8 pci_bus;
u8 pci_dev_func;
u8 irq;
struct pci_dev *pdev = NULL;
u8 did_ioremap_f = 0;
u8 did_req_region_f = 0;
u8 did_scsi_reg_f = 0;
u8 alloc_int_buf_f = 0;
u8 alloc_scb_f = 0;
u8 got_irq_f = 0;
u8 did_setup_mbox_f = 0;
unsigned long tbase;
unsigned long flag = 0;
int i, j;
while((pdev = pci_find_device(pci_vendor, pci_device, pdev))) {
if(pci_enable_device (pdev)) continue;
pci_bus = pdev->bus->number;
pci_dev_func = pdev->devfn;
/*
* For these vendor and device ids, signature offsets are not
* valid and 64 bit is implicit
*/
if( (pci_vendor == PCI_VENDOR_ID_DELL &&
pci_device == PCI_DEVICE_ID_PERC4_DI) ||
(pci_vendor == PCI_VENDOR_ID_LSI_LOGIC &&
pci_device == PCI_DEVICE_ID_PERC4_QC_VERDE) ) {
dma_addr_t prod_info_dma_handle;
mega_inquiry3 *inquiry3;
u8 raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
int retval;
flag |= BOARD_64BIT;
}
else {
pci_read_config_dword(pdev, PCI_CONF_AMISIG64,
&magic64);
/* Initialize adapter inquiry mailbox */
if (magic64 == HBA_SIGNATURE_64BIT)
flag |= BOARD_64BIT;
}
mbox = (mbox_t *)raw_mbox;
subsysvid = pdev->subsystem_vendor;
subsysid = pdev->subsystem_device;
memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
memset(&mbox->m_out, 0, sizeof(raw_mbox));
/*
* If we do not find the valid subsys vendor id, refuse to
* load the driver. This is part of PCI200X compliance
* We load the driver if subsysvid is 0.
* Try to issue Inquiry3 command
* if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
* update enquiry3 structure
*/
if( subsysvid && (subsysvid != AMI_SUBSYS_VID) &&
(subsysvid != DELL_SUBSYS_VID) &&
(subsysvid != HP_SUBSYS_VID) &&
(subsysvid != INTEL_SUBSYS_VID) &&
(subsysvid != LSI_SUBSYS_VID) ) continue;
printk(KERN_NOTICE "megaraid: found 0x%4.04x:0x%4.04x:bus %d:",
pci_vendor, pci_device, pci_bus);
mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
printk("slot %d:func %d\n",
PCI_SLOT(pci_dev_func), PCI_FUNC(pci_dev_func));
inquiry3 = (mega_inquiry3 *)adapter->mega_buffer;
/* Read the base port and IRQ from PCI */
mega_baseport = pci_resource_start(pdev, 0);
irq = pdev->irq;
raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */
raw_mbox[2] = NC_SUBOP_ENQUIRY3; /* i.e. 0x0F */
raw_mbox[3] = ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */
tbase = mega_baseport;
/* Issue a blocking command to the card */
if ((retval = issue_scb_block(adapter, raw_mbox))) {
/* the adapter does not support 40ld */
if( pci_resource_flags(pdev, 0) & IORESOURCE_MEM ) {
mraid_ext_inquiry *ext_inq;
mraid_inquiry *inq;
dma_addr_t dma_handle;
if (!request_mem_region(mega_baseport, 128,
"MegaRAID: LSI Logic Corporation.")) {
printk(KERN_WARNING
"megaraid: mem region busy!\n");
continue;
}
ext_inq = pci_alloc_consistent(adapter->dev,
sizeof(mraid_ext_inquiry), &dma_handle);
mega_baseport =
(unsigned long)ioremap(mega_baseport, 128);
if( ext_inq == NULL ) return -1;
if( !mega_baseport ) {
printk(KERN_WARNING
"megaraid: could not map hba memory\n");
inq = &ext_inq->raid_inq;
release_mem_region(tbase, 128);
mbox->m_out.xferaddr = (u32)dma_handle;
continue;
}
/*issue old 0x04 command to adapter */
mbox->m_out.cmd = MEGA_MBOXCMD_ADPEXTINQ;
flag |= BOARD_MEMMAP;
issue_scb_block(adapter, raw_mbox);
did_ioremap_f = 1;
}
else {
mega_baseport += 0x10;
/*
* update Enquiry3 and ProductInfo structures with
* mraid_inquiry structure
*/
mega_8_to_40ld(inq, inquiry3,
(mega_product_info *)&adapter->product_info);
if( !request_region(mega_baseport, 16, "megaraid") )
goto fail_attach;
pci_free_consistent(adapter->dev, sizeof(mraid_ext_inquiry),
ext_inq, dma_handle);
flag |= BOARD_IOMAP;
} else { /*adapter supports 40ld */
adapter->flag |= BOARD_40LD;
did_req_region_f = 1;
}
/*
* get product_info, which is static information and will be
* unchanged
*/
prod_info_dma_handle = pci_map_single(adapter->dev, (void *)
&adapter->product_info,
sizeof(mega_product_info), PCI_DMA_FROMDEVICE);
/* Initialize SCSI Host structure */
host = scsi_register(host_template, sizeof(adapter_t));
mbox->m_out.xferaddr = prod_info_dma_handle;
if(!host) goto fail_attach;
raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */
raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */
did_scsi_reg_f = 1;
if ((retval = issue_scb_block(adapter, raw_mbox)))
printk(KERN_WARNING
"megaraid: Product_info cmd failed with error: %d\n",
retval);
scsi_set_device(host, &pdev->dev);
pci_dma_sync_single(adapter->dev, prod_info_dma_handle,
sizeof(mega_product_info),
PCI_DMA_FROMDEVICE);
adapter = (adapter_t *)host->hostdata;
memset(adapter, 0, sizeof(adapter_t));
pci_unmap_single(adapter->dev, prod_info_dma_handle,
sizeof(mega_product_info), PCI_DMA_FROMDEVICE);
}
printk(KERN_NOTICE
"scsi%d:Found MegaRAID controller at 0x%lx, IRQ:%d\n",
host->host_no, mega_baseport, irq);
adapter->base = mega_baseport;
/*
* kernel scans the channels from 0 to <= max_channel
*/
adapter->host->max_channel =
adapter->product_info.nchannels + NVIRT_CHAN -1;
/* Copy resource info into structure */
INIT_LIST_HEAD(&adapter->free_list);
INIT_LIST_HEAD(&adapter->pending_list);
INIT_LIST_HEAD(&adapter->completed_list);
adapter->host->max_id = 16; /* max targets per channel */
adapter->flag = flag;
spin_lock_init(&adapter->lock);
scsi_assign_lock(host, &adapter->lock);
adapter->host->max_lun = 7; /* Upto 7 luns for non disk devices */
host->cmd_per_lun = max_cmd_per_lun;
host->max_sectors = max_sectors_per_io;
adapter->host->cmd_per_lun = max_cmd_per_lun;
adapter->dev = pdev;
adapter->host = host;
adapter->numldrv = inquiry3->num_ldrv;
adapter->host->irq = irq;
adapter->max_cmds = adapter->product_info.max_commands;
if( flag & BOARD_MEMMAP ) {
adapter->host->base = tbase;
}
else {
adapter->host->io_port = tbase;
adapter->host->n_io_port = 16;
}
if(adapter->max_cmds > MAX_COMMANDS)
adapter->max_cmds = MAX_COMMANDS;
adapter->host->unique_id = (pci_bus << 8) | pci_dev_func;
adapter->host->can_queue = adapter->max_cmds - 1;
/*
* Allocate buffer to issue internal commands.
* Get the maximum number of scatter-gather elements supported by this
* firmware
*/
adapter->mega_buffer = pci_alloc_consistent(adapter->dev,
MEGA_BUFFER_SIZE, &adapter->buf_dma_handle);
mega_get_max_sgl(adapter);
if( !adapter->mega_buffer ) {
printk(KERN_WARNING "megaraid: out of RAM.\n");
goto fail_attach;
}
alloc_int_buf_f = 1;
adapter->host->sg_tablesize = adapter->sglen;
adapter->scb_list = kmalloc(sizeof(scb_t)*MAX_COMMANDS,
GFP_KERNEL);
if(!adapter->scb_list) {
printk(KERN_WARNING "megaraid: out of RAM.\n");
goto fail_attach;
}
/* use HP firmware and bios version encoding */
if (adapter->product_info.subsysvid == HP_SUBSYS_VID) {
sprintf (adapter->fw_version, "%c%d%d.%d%d",
adapter->product_info.fw_version[2],
adapter->product_info.fw_version[1] >> 8,
adapter->product_info.fw_version[1] & 0x0f,
adapter->product_info.fw_version[0] >> 8,
adapter->product_info.fw_version[0] & 0x0f);
sprintf (adapter->bios_version, "%c%d%d.%d%d",
adapter->product_info.bios_version[2],
adapter->product_info.bios_version[1] >> 8,
adapter->product_info.bios_version[1] & 0x0f,
adapter->product_info.bios_version[0] >> 8,
adapter->product_info.bios_version[0] & 0x0f);
} else {
memcpy(adapter->fw_version,
(char *)adapter->product_info.fw_version, 4);
adapter->fw_version[4] = 0;
alloc_scb_f = 1;
memcpy(adapter->bios_version,
(char *)adapter->product_info.bios_version, 4);
/* Request our IRQ */
if( adapter->flag & BOARD_MEMMAP ) {
if(request_irq(irq, megaraid_isr_memmapped, SA_SHIRQ,
"megaraid", adapter)) {
printk(KERN_WARNING
"megaraid: Couldn't register IRQ %d!\n",
irq);
goto fail_attach;
}
adapter->bios_version[4] = 0;
}
else {
if(request_irq(irq, megaraid_isr_iomapped, SA_SHIRQ,
"megaraid", adapter)) {
printk(KERN_WARNING
"megaraid: Couldn't register IRQ %d!\n",
irq);
goto fail_attach;
}
}
got_irq_f = 1;
if( mega_setup_mailbox(adapter) != 0 )
goto fail_attach;
did_setup_mbox_f = 1;
if( mega_query_adapter(adapter) != 0 )
goto fail_attach;
printk(KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives.\n",
adapter->fw_version, adapter->bios_version, adapter->numldrv);
/*
* Have checks for some buggy f/w
*/
if((subsysid == 0x1111) && (subsysvid == 0x1111)) {
/*
* Which firmware
* Do we support extended (>10 bytes) cdbs
*/
if (!strcmp(adapter->fw_version, "3.00") ||
!strcmp(adapter->fw_version, "3.01")) {
adapter->support_ext_cdb = mega_support_ext_cdb(adapter);
if (adapter->support_ext_cdb)
printk(KERN_NOTICE "megaraid: supports extended CDBs.\n");
printk( KERN_WARNING
"megaraid: Your card is a Dell PERC "
"2/SC RAID controller with "
"firmware\nmegaraid: 3.00 or 3.01. "
"This driver is known to have "
"corruption issues\nmegaraid: with "
"those firmware versions on this "
"specific card. In order\nmegaraid: "
"to protect your data, please upgrade "
"your firmware to version\nmegaraid: "
"3.10 or later, available from the "
"Dell Technical Support web\n"
"megaraid: site at\nhttp://support."
"dell.com/us/en/filelib/download/"
"index.asp?fileid=2940\n"
);
}
}
/*
* If we have a HP 1M(0x60E7)/2M(0x60E8) controller with
* firmware H.01.07, H.01.08, and H.01.09 disable 64 bit
* support, since this firmware cannot handle 64 bit
* addressing
*/
return 0;
}
if((subsysvid == HP_SUBSYS_VID) &&
((subsysid == 0x60E7)||(subsysid == 0x60E8))) {
/*
* which firmware
/*
* megaraid_queue()
* @scmd - Issue this scsi command
* @done - the callback hook into the scsi mid-layer
*
* The command queuing entry point for the mid-layer.
*/
if( !strcmp(adapter->fw_version, "H01.07") ||
!strcmp(adapter->fw_version, "H01.08") ||
!strcmp(adapter->fw_version, "H01.09") ) {
printk(KERN_WARNING
"megaraid: Firmware H.01.07, "
"H.01.08, and H.01.09 on 1M/2M "
"controllers\n"
"megaraid: do not support 64 bit "
"addressing.\nmegaraid: DISABLING "
"64 bit support.\n");
adapter->flag &= ~BOARD_64BIT;
}
}
static int
megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
{
adapter_t *adapter;
scb_t *scb;
int busy=0;
adapter = (adapter_t *)scmd->device->host->hostdata;
if(mega_is_bios_enabled(adapter)) {
mega_hbas[hba_count].is_bios_enabled = 1;
}
mega_hbas[hba_count].hostdata_addr = adapter;
scmd->scsi_done = done;
/*
* Find out which channel is raid and which is scsi. This is
* for ROMB support.
*/
mega_enum_raid_scsi(adapter);
/*
* Find out if a logical drive is set as the boot drive. If
* there is one, will make that as the first logical drive.
* ROMB: Do we have to boot from a physical drive. Then all
* the physical drives would appear before the logical disks.
* Else, all the physical drives would be exported to the mid
* layer after logical drives.
* Allocate and build a SCB request
* busy flag will be set if mega_build_cmd() command could not
* allocate scb. We will return non-zero status in that case.
* NOTE: scb can be null even though certain commands completed
* successfully, e.g., MODE_SENSE and TEST_UNIT_READY, we would
* return 0 in that case.
*/
mega_get_boot_drv(adapter);
if( ! adapter->boot_pdrv_enabled ) {
for( i = 0; i < NVIRT_CHAN; i++ )
adapter->logdrv_chan[i] = 1;
scb = mega_build_cmd(adapter, scmd, &busy);
for( i = NVIRT_CHAN; i<MAX_CHANNELS+NVIRT_CHAN; i++ )
adapter->logdrv_chan[i] = 0;
if(scb) {
scb->state |= SCB_PENDQ;
list_add_tail(&scb->list, &adapter->pending_list);
adapter->mega_ch_class <<= NVIRT_CHAN;
/*
* 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);
}
else {
j = adapter->product_info.nchannels;
for( i = 0; i < j; i++ )
adapter->logdrv_chan[i] = 0;
for( i = j; i < NVIRT_CHAN + j; i++ )
adapter->logdrv_chan[i] = 1;
return 0;
}
return busy;
}
/*
* Do we support random deletion and addition of logical
* drives
/**
* mega_build_cmd()
* @adapter - pointer to our soft state
* @cmd - Prepare using this scsi command
* @busy - busy flag if no resources
*
* Prepares a command and scatter gather list for the controller. This routine
* also finds out if the commands is intended for a logical drive or a
* physical device and prepares the controller command accordingly.
*
* We also re-order the logical drives and physical devices based on their
* boot settings.
*/
adapter->read_ldidmap = 0; /* set it after first logdrv
delete cmd */
adapter->support_random_del = mega_support_random_del(adapter);
static scb_t *
mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
{
mega_ext_passthru *epthru;
mega_passthru *pthru;
scb_t *scb;
mbox_t *mbox;
long seg;
char islogical;
int max_ldrv_num;
int channel = 0;
int target = 0;
int ldrv_num = 0; /* logical drive number */
/* Initialize SCBs */
if(mega_init_scb(adapter)) {
goto fail_attach;
}
/*
* Reset the pending commands counter
* filter the internal and ioctl commands
*/
atomic_set(&adapter->pend_cmds, 0);
if((cmd->cmnd[0] == MEGA_INTERNAL_CMD)) {
return cmd->buffer;
}
/*
* Reset the adapter quiescent flag
* We know what channels our logical drives are on - mega_find_card()
*/
atomic_set(&adapter->quiescent, 0);
hba_soft_state[hba_count] = adapter;
islogical = adapter->logdrv_chan[cmd->device->channel];
/*
* Fill in the structure which needs to be passed back to the
* application when it does an ioctl() for controller related
* information.
* The theory: If physical drive is chosen for boot, all the physical
* devices are exported before the logical drives, otherwise physical
* devices are pushed after logical drives, in which case - Kernel sees
* the physical devices on virtual channel which is obviously converted
* to actual channel on the HBA.
*/
i = hba_count;
mcontroller[i].base = mega_baseport;
mcontroller[i].irq = irq;
mcontroller[i].numldrv = adapter->numldrv;
mcontroller[i].pcibus = pci_bus;
mcontroller[i].pcidev = pci_device;
mcontroller[i].pcifun = PCI_FUNC (pci_dev_func);
mcontroller[i].pciid = -1;
mcontroller[i].pcivendor = pci_vendor;
mcontroller[i].pcislot = PCI_SLOT (pci_dev_func);
mcontroller[i].uid = (pci_bus << 8) | pci_dev_func;
/* 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);
adapter->has_64bit_addr = 1;
if( adapter->boot_pdrv_enabled ) {
if( islogical ) {
/* logical channel */
channel = cmd->device->channel -
adapter->product_info.nchannels;
}
else {
pci_set_dma_mask(pdev, 0xffffffff);
adapter->has_64bit_addr = 0;
}
init_MUTEX(&adapter->int_mtx);
init_waitqueue_head(&adapter->int_waitq);
adapter->this_id = DEFAULT_INITIATOR_ID;
adapter->host->this_id = DEFAULT_INITIATOR_ID;
/* this is physical channel */
channel = cmd->device->channel;
target = cmd->device->id;
#if MEGA_HAVE_CLUSTERING
/*
* Is cluster support enabled on this controller
* Note: In a cluster the HBAs ( the initiators ) will have
* different target IDs and we cannot assume it to be 7. Call
* to mega_support_cluster() will get the target ids also if
* the cluster support is available
* boot from a physical disk, that disk needs to be
* exposed first IF both the channels are SCSI, then
* booting from the second channel is not allowed.
*/
adapter->has_cluster = mega_support_cluster(adapter);
if( adapter->has_cluster ) {
printk(KERN_NOTICE
"megaraid: Cluster driver, initiator id:%d\n",
adapter->this_id);
if( target == 0 ) {
target = adapter->boot_pdrv_tgt;
}
#endif
hba_count++;
continue;
fail_attach:
if( did_setup_mbox_f ) {
pci_free_consistent(adapter->dev, sizeof(mbox64_t),
(void *)adapter->una_mbox64,
adapter->una_mbox64_dma);
else if( target == adapter->boot_pdrv_tgt ) {
target = 0;
}
if( got_irq_f ) {
irq_disable(adapter);
free_irq(adapter->host->irq, adapter);
}
if( alloc_scb_f ) {
kfree(adapter->scb_list);
}
if( alloc_int_buf_f ) {
pci_free_consistent(adapter->dev, MEGA_BUFFER_SIZE,
(void *)adapter->mega_buffer,
adapter->buf_dma_handle);
else {
if( islogical ) {
/* this is the logical channel */
channel = cmd->device->channel;
}
if( did_scsi_reg_f ) scsi_unregister(host);
if( did_ioremap_f ) {
iounmap((void *)mega_baseport);
release_mem_region(tbase, 128);
else {
/* physical channel */
channel = cmd->device->channel - NVIRT_CHAN;
target = cmd->device->id;
}
if( did_req_region_f )
release_region(mega_baseport, 16);
}
return;
}
if(islogical) {
/**
* mega_setup_mailbox()
* @adapter - pointer to our soft state
*
* Allocates a 8 byte aligned memory for the handshake mailbox.
*/
static int
mega_setup_mailbox(adapter_t *adapter)
{
unsigned long align;
adapter->una_mbox64 = pci_alloc_consistent(adapter->dev,
sizeof(mbox64_t), &adapter->una_mbox64_dma);
if( !adapter->una_mbox64 ) return -1;
adapter->mbox = &adapter->una_mbox64->mbox;
adapter->mbox = (mbox_t *)((((unsigned long) adapter->mbox) + 15) &
(~0UL ^ 0xFUL));
/* have just LUN 0 for each target on virtual channels */
if (cmd->device->lun) {
cmd->result = (DID_BAD_TARGET << 16);
cmd->scsi_done(cmd);
return NULL;
}
adapter->mbox64 = (mbox64_t *)(((unsigned long)adapter->mbox) - 8);
ldrv_num = mega_get_ldrv_num(adapter, cmd, channel);
align = ((void *)adapter->mbox) - ((void *)&adapter->una_mbox64->mbox);
adapter->mbox_dma = adapter->una_mbox64_dma + 8 + align;
max_ldrv_num = (adapter->flag & BOARD_40LD) ?
MAX_LOGICAL_DRIVES_40LD : MAX_LOGICAL_DRIVES_8LD;
/*
* Register the mailbox if the controller is an io-mapped controller
* max_ldrv_num increases by 0x80 if some logical drive was
* deleted.
*/
if( adapter->flag & BOARD_IOMAP ) {
outb_p(adapter->mbox_dma & 0xFF,
adapter->host->io_port + MBOX_PORT0);
outb_p((adapter->mbox_dma >> 8) & 0xFF,
adapter->host->io_port + MBOX_PORT1);
outb_p((adapter->mbox_dma >> 16) & 0xFF,
adapter->host->io_port + MBOX_PORT2);
outb_p((adapter->mbox_dma >> 24) & 0xFF,
adapter->host->io_port + MBOX_PORT3);
outb_p(ENABLE_MBOX_BYTE,
adapter->host->io_port + ENABLE_MBOX_REGION);
irq_ack(adapter);
if(adapter->read_ldidmap)
max_ldrv_num += 0x80;
irq_enable(adapter);
if(ldrv_num > max_ldrv_num ) {
cmd->result = (DID_BAD_TARGET << 16);
cmd->scsi_done(cmd);
return NULL;
}
return 0;
}
}
else {
if( cmd->device->lun > 7) {
/*
* Do not support lun >7 for physically accessed
* devices
*/
cmd->result = (DID_BAD_TARGET << 16);
cmd->scsi_done(cmd);
return NULL;
}
}
/*
* mega_query_adapter()
* @adapter - pointer to our soft state
/*
*
* Logical drive commands
*
* Issue the adapter inquiry commands to the controller and find out
* information and parameter about the devices attached
*/
static int
mega_query_adapter(adapter_t *adapter)
{
dma_addr_t prod_info_dma_handle;
mega_inquiry3 *inquiry3;
u8 raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
int retval;
/* Initialize adapter inquiry mailbox */
mbox = (mbox_t *)raw_mbox;
memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
memset(&mbox->m_out, 0, sizeof(raw_mbox));
if(islogical) {
switch (cmd->cmnd[0]) {
case TEST_UNIT_READY:
memset(cmd->request_buffer, 0, cmd->request_bufflen);
#if MEGA_HAVE_CLUSTERING
/*
* Try to issue Inquiry3 command
* if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
* update enquiry3 structure
* Do we support clustering and is the support enabled
* If no, return success always
*/
mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
inquiry3 = (mega_inquiry3 *)adapter->mega_buffer;
raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */
raw_mbox[2] = NC_SUBOP_ENQUIRY3; /* i.e. 0x0F */
raw_mbox[3] = ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */
if( !adapter->has_cluster ) {
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
}
/* Issue a blocking command to the card */
if ((retval = issue_scb_block(adapter, raw_mbox))) {
/* the adapter does not support 40ld */
if(!(scb = mega_allocate_scb(adapter, cmd))) {
mraid_ext_inquiry *ext_inq;
mraid_inquiry *inq;
dma_addr_t dma_handle;
cmd->result = (DID_ERROR << 16);
cmd->scsi_done(cmd);
*busy = 1;
ext_inq = pci_alloc_consistent(adapter->dev,
sizeof(mraid_ext_inquiry), &dma_handle);
return NULL;
}
if( ext_inq == NULL ) return -1;
scb->raw_mbox[0] = MEGA_CLUSTER_CMD;
scb->raw_mbox[2] = MEGA_RESERVATION_STATUS;
scb->raw_mbox[3] = ldrv_num;
inq = &ext_inq->raid_inq;
scb->dma_direction = PCI_DMA_NONE;
mbox->m_out.xferaddr = (u32)dma_handle;
return scb;
#else
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
#endif
/*issue old 0x04 command to adapter */
mbox->m_out.cmd = MEGA_MBOXCMD_ADPEXTINQ;
case MODE_SENSE:
memset(cmd->request_buffer, 0, cmd->cmnd[4]);
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
issue_scb_block(adapter, raw_mbox);
case READ_CAPACITY:
case INQUIRY:
/*
* update Enquiry3 and ProductInfo structures with
* mraid_inquiry structure
*/
mega_8_to_40ld(inq, inquiry3,
(mega_product_info *)&adapter->product_info);
if(!(adapter->flag & (1L << cmd->device->channel))) {
pci_free_consistent(adapter->dev, sizeof(mraid_ext_inquiry),
ext_inq, dma_handle);
printk(KERN_NOTICE
"scsi%d: scanning scsi channel %d ",
adapter->host->host_no,
cmd->device->channel);
printk("for logical drives.\n");
} else { /*adapter supports 40ld */
adapter->flag |= BOARD_40LD;
adapter->flag |= (1L << cmd->device->channel);
}
/*
* get product_info, which is static information and will be
* unchanged
*/
prod_info_dma_handle = pci_map_single(adapter->dev, (void *)
&adapter->product_info,
sizeof(mega_product_info), PCI_DMA_FROMDEVICE);
/* Allocate a SCB and initialize passthru */
if(!(scb = mega_allocate_scb(adapter, cmd))) {
mbox->m_out.xferaddr = prod_info_dma_handle;
cmd->result = (DID_ERROR << 16);
cmd->scsi_done(cmd);
*busy = 1;
raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */
raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */
return NULL;
}
pthru = scb->pthru;
if ((retval = issue_scb_block(adapter, raw_mbox)))
printk(KERN_WARNING
"megaraid: Product_info cmd failed with error: %d\n",
retval);
mbox = (mbox_t *)scb->raw_mbox;
memset(mbox, 0, sizeof(scb->raw_mbox));
memset(pthru, 0, sizeof(mega_passthru));
pci_dma_sync_single(adapter->dev, prod_info_dma_handle,
sizeof(mega_product_info),
PCI_DMA_FROMDEVICE);
pthru->timeout = 0;
pthru->ars = 1;
pthru->reqsenselen = 14;
pthru->islogical = 1;
pthru->logdrv = ldrv_num;
pthru->cdblen = cmd->cmd_len;
memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len);
pci_unmap_single(adapter->dev, prod_info_dma_handle,
sizeof(mega_product_info), PCI_DMA_FROMDEVICE);
if( adapter->has_64bit_addr ) {
mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64;
}
else {
mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU;
}
scb->dma_direction = PCI_DMA_FROMDEVICE;
/*
* kernel scans the channels from 0 to <= max_channel
*/
adapter->host->max_channel =
adapter->product_info.nchannels + NVIRT_CHAN -1;
pthru->numsgelements = mega_build_sglist(adapter, scb,
&pthru->dataxferaddr, &pthru->dataxferlen);
adapter->host->max_id = 16; /* max targets per channel */
mbox->m_out.xferaddr = scb->pthru_dma_addr;
adapter->host->max_lun = 7; /* Upto 7 luns for non disk devices */
return scb;
adapter->host->cmd_per_lun = max_cmd_per_lun;
case READ_6:
case WRITE_6:
case READ_10:
case WRITE_10:
case READ_12:
case WRITE_12:
adapter->numldrv = inquiry3->num_ldrv;
/* Allocate a SCB and initialize mailbox */
if(!(scb = mega_allocate_scb(adapter, cmd))) {
adapter->max_cmds = adapter->product_info.max_commands;
cmd->result = (DID_ERROR << 16);
cmd->scsi_done(cmd);
*busy = 1;
if(adapter->max_cmds > MAX_COMMANDS)
adapter->max_cmds = MAX_COMMANDS;
return NULL;
}
mbox = (mbox_t *)scb->raw_mbox;
adapter->host->can_queue = adapter->max_cmds - 1;
memset(mbox, 0, sizeof(scb->raw_mbox));
mbox->m_out.logdrv = ldrv_num;
/*
* Get the maximum number of scatter-gather elements supported by this
* firmware
*/
mega_get_max_sgl(adapter);
adapter->host->sg_tablesize = adapter->sglen;
/* use HP firmware and bios version encoding */
if (adapter->product_info.subsysvid == HP_SUBSYS_VID) {
sprintf (adapter->fw_version, "%c%d%d.%d%d",
adapter->product_info.fw_version[2],
adapter->product_info.fw_version[1] >> 8,
adapter->product_info.fw_version[1] & 0x0f,
adapter->product_info.fw_version[0] >> 8,
adapter->product_info.fw_version[0] & 0x0f);
sprintf (adapter->bios_version, "%c%d%d.%d%d",
adapter->product_info.bios_version[2],
adapter->product_info.bios_version[1] >> 8,
adapter->product_info.bios_version[1] & 0x0f,
adapter->product_info.bios_version[0] >> 8,
adapter->product_info.bios_version[0] & 0x0f);
} else {
memcpy(adapter->fw_version,
(char *)adapter->product_info.fw_version, 4);
adapter->fw_version[4] = 0;
memcpy(adapter->bios_version,
(char *)adapter->product_info.bios_version, 4);
adapter->bios_version[4] = 0;
}
printk(KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives.\n",
adapter->fw_version, adapter->bios_version, adapter->numldrv);
/*
* Do we support extended (>10 bytes) cdbs
*/
adapter->support_ext_cdb = mega_support_ext_cdb(adapter);
if (adapter->support_ext_cdb)
printk(KERN_NOTICE "megaraid: supports extended CDBs.\n");
return 0;
}
/*
* megaraid_queue()
* @scmd - Issue this scsi command
* @done - the callback hook into the scsi mid-layer
*
* The command queuing entry point for the mid-layer.
*/
static int
megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
{
adapter_t *adapter;
scb_t *scb;
int busy=0;
adapter = (adapter_t *)scmd->device->host->hostdata;
scmd->scsi_done = done;
/*
* Allocate and build a SCB request
* busy flag will be set if mega_build_cmd() command could not
* allocate scb. We will return non-zero status in that case.
* NOTE: scb can be null even though certain commands completed
* successfully, e.g., MODE_SENSE and TEST_UNIT_READY, we would
* return 0 in that case.
*/
scb = mega_build_cmd(adapter, scmd, &busy);
if(scb) {
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;
}
return busy;
}
/**
* mega_build_cmd()
* @adapter - pointer to our soft state
* @cmd - Prepare using this scsi command
* @busy - busy flag if no resources
*
* Prepares a command and scatter gather list for the controller. This routine
* also finds out if the commands is intended for a logical drive or a
* physical device and prepares the controller command accordingly.
*
* We also re-order the logical drives and physical devices based on their
* boot settings.
*/
static scb_t *
mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
{
mega_ext_passthru *epthru;
mega_passthru *pthru;
scb_t *scb;
mbox_t *mbox;
long seg;
char islogical;
int max_ldrv_num;
int channel = 0;
int target = 0;
int ldrv_num = 0; /* logical drive number */
/*
* filter the internal and ioctl commands
*/
if((cmd->cmnd[0] == MEGA_INTERNAL_CMD)) {
return cmd->buffer;
}
/*
* We know what channels our logical drives are on - mega_find_card()
*/
islogical = adapter->logdrv_chan[cmd->device->channel];
/*
* The theory: If physical drive is chosen for boot, all the physical
* devices are exported before the logical drives, otherwise physical
* devices are pushed after logical drives, in which case - Kernel sees
* the physical devices on virtual channel which is obviously converted
* to actual channel on the HBA.
*/
if( adapter->boot_pdrv_enabled ) {
if( islogical ) {
/* logical channel */
channel = cmd->device->channel -
adapter->product_info.nchannels;
}
else {
/* this is physical channel */
channel = cmd->device->channel;
target = cmd->device->id;
/*
* boot from a physical disk, that disk needs to be
* exposed first IF both the channels are SCSI, then
* booting from the second channel is not allowed.
*/
if( target == 0 ) {
target = adapter->boot_pdrv_tgt;
}
else if( target == adapter->boot_pdrv_tgt ) {
target = 0;
}
}
}
else {
if( islogical ) {
/* this is the logical channel */
channel = cmd->device->channel;
}
else {
/* physical channel */
channel = cmd->device->channel - NVIRT_CHAN;
target = cmd->device->id;
}
}
if(islogical) {
/* have just LUN 0 for each target on virtual channels */
if (cmd->device->lun) {
cmd->result = (DID_BAD_TARGET << 16);
cmd->scsi_done(cmd);
return NULL;
}
ldrv_num = mega_get_ldrv_num(adapter, cmd, channel);
max_ldrv_num = (adapter->flag & BOARD_40LD) ?
MAX_LOGICAL_DRIVES_40LD : MAX_LOGICAL_DRIVES_8LD;
/*
* max_ldrv_num increases by 0x80 if some logical drive was
* deleted.
*/
if(adapter->read_ldidmap)
max_ldrv_num += 0x80;
if(ldrv_num > max_ldrv_num ) {
cmd->result = (DID_BAD_TARGET << 16);
cmd->scsi_done(cmd);
return NULL;
}
}
else {
if( cmd->device->lun > 7) {
/*
* Do not support lun >7 for physically accessed
* devices
*/
cmd->result = (DID_BAD_TARGET << 16);
cmd->scsi_done(cmd);
return NULL;
}
}
/*
*
* Logical drive commands
*
*/
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 no, return success always
*/
if( !adapter->has_cluster ) {
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
}
if(!(scb = mega_allocate_scb(adapter, cmd))) {
cmd->result = (DID_ERROR << 16);
cmd->scsi_done(cmd);
*busy = 1;
return NULL;
}
scb->raw_mbox[0] = MEGA_CLUSTER_CMD;
scb->raw_mbox[2] = MEGA_RESERVATION_STATUS;
scb->raw_mbox[3] = ldrv_num;
scb->dma_direction = PCI_DMA_NONE;
return scb;
#else
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
#endif
case MODE_SENSE:
memset(cmd->request_buffer, 0, cmd->cmnd[4]);
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
case READ_CAPACITY:
case INQUIRY:
if(!(adapter->flag & (1L << cmd->device->channel))) {
printk(KERN_NOTICE
"scsi%d: scanning scsi channel %d ",
adapter->host->host_no,
cmd->device->channel);
printk("for logical drives.\n");
adapter->flag |= (1L << cmd->device->channel);
}
/* 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;
mbox = (mbox_t *)scb->raw_mbox;
memset(mbox, 0, sizeof(scb->raw_mbox));
memset(pthru, 0, sizeof(mega_passthru));
pthru->timeout = 0;
pthru->ars = 1;
pthru->reqsenselen = 14;
pthru->islogical = 1;
pthru->logdrv = ldrv_num;
pthru->cdblen = cmd->cmd_len;
memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len);
if( adapter->has_64bit_addr ) {
mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64;
}
else {
mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU;
}
scb->dma_direction = PCI_DMA_FROMDEVICE;
pthru->numsgelements = mega_build_sglist(adapter, scb,
&pthru->dataxferaddr, &pthru->dataxferlen);
mbox->m_out.xferaddr = scb->pthru_dma_addr;
return scb;
case READ_6:
case WRITE_6:
case READ_10:
case WRITE_10:
case READ_12:
case WRITE_12:
/* 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;
memset(mbox, 0, sizeof(scb->raw_mbox));
mbox->m_out.logdrv = ldrv_num;
/*
* A little hack: 2nd bit is zero for all scsi read
* commands and is set for all scsi write commands
* A little hack: 2nd bit is zero for all scsi read
* commands and is set for all scsi write commands
*/
if( adapter->has_64bit_addr ) {
mbox->m_out.cmd = (*cmd->cmnd & 0x02) ?
......@@ -2396,126 +1853,6 @@ mega_8_to_40ld(mraid_inquiry *inquiry, mega_inquiry3 *enquiry3,
enquiry3->pdrv_state[i] = inquiry->pdrv_info.pdrv_state[i];
}
/*
* Release the controller's resources
*/
static int
megaraid_release(struct Scsi_Host *host)
{
adapter_t *adapter;
mbox_t *mbox;
u_char raw_mbox[sizeof(struct mbox_out)];
char buf[12] = { 0 };
adapter = (adapter_t *)host->hostdata;
mbox = (mbox_t *)raw_mbox;
printk(KERN_NOTICE "megaraid: being unloaded...");
/* Flush adapter cache */
memset(&mbox->m_out, 0, sizeof(raw_mbox));
raw_mbox[0] = FLUSH_ADAPTER;
irq_disable(adapter);
free_irq(adapter->host->irq, adapter);
/* Issue a blocking (interrupts disabled) command to the card */
issue_scb_block(adapter, raw_mbox);
/* Flush disks cache */
memset(&mbox->m_out, 0, sizeof(raw_mbox));
raw_mbox[0] = FLUSH_SYSTEM;
/* Issue a blocking (interrupts disabled) command to the card */
issue_scb_block(adapter, raw_mbox);
/* Free our resources */
if( adapter->flag & BOARD_MEMMAP ) {
iounmap((void *)adapter->base);
release_mem_region(adapter->host->base, 128);
}
else {
release_region(adapter->base, 16);
}
mega_free_sgl(adapter);
#ifdef CONFIG_PROC_FS
if( adapter->controller_proc_dir_entry ) {
remove_proc_entry("stat", adapter->controller_proc_dir_entry);
remove_proc_entry("config",
adapter->controller_proc_dir_entry);
remove_proc_entry("mailbox",
adapter->controller_proc_dir_entry);
#if MEGA_HAVE_ENH_PROC
remove_proc_entry("rebuild-rate",
adapter->controller_proc_dir_entry);
remove_proc_entry("battery-status",
adapter->controller_proc_dir_entry);
remove_proc_entry("diskdrives-ch0",
adapter->controller_proc_dir_entry);
remove_proc_entry("diskdrives-ch1",
adapter->controller_proc_dir_entry);
remove_proc_entry("diskdrives-ch2",
adapter->controller_proc_dir_entry);
remove_proc_entry("diskdrives-ch3",
adapter->controller_proc_dir_entry);
remove_proc_entry("raiddrives-0-9",
adapter->controller_proc_dir_entry);
remove_proc_entry("raiddrives-10-19",
adapter->controller_proc_dir_entry);
remove_proc_entry("raiddrives-20-29",
adapter->controller_proc_dir_entry);
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);
}
#endif
pci_free_consistent(adapter->dev, MEGA_BUFFER_SIZE,
adapter->mega_buffer, adapter->buf_dma_handle);
kfree(adapter->scb_list);
pci_free_consistent(adapter->dev, sizeof(mbox64_t),
(void *)adapter->una_mbox64, adapter->una_mbox64_dma);
hba_count--;
if( hba_count == 0 ) {
/*
* Unregister the character device interface to the driver.
*/
unregister_chrdev(major, "megadev");
unregister_reboot_notifier(&mega_notifier);
#ifdef CONFIG_PROC_FS
if( adapter->controller_proc_dir_entry ) {
remove_proc_entry ("megaraid", &proc_root);
}
#endif
}
/*
* Release the controller memory. A word of warning this frees
* hostdata and that includes adapter-> so be careful what you
* dereference beyond this point
*/
scsi_unregister(host);
printk("ok.\n");
return 0;
}
static inline void
mega_free_sgl(adapter_t *adapter)
{
......@@ -3842,81 +3179,11 @@ megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev,
/* return result */
geom[0] = heads;
geom[1] = sectors;
geom[2] = cylinders;
}
return 0;
}
/**
* megaraid_reboot_notify()
* @this - unused
* @code - shutdown code
* @unused - unused
*
* This routine will be called when the use has done a forced shutdown on the
* system. Flush the Adapter and disks cache.
*/
static int
megaraid_reboot_notify (struct notifier_block *this, unsigned long code,
void *unused)
{
adapter_t *adapter;
struct Scsi_Host *host;
u8 raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
int i,j;
/*
* Flush the controller's cache irrespective of the codes coming down.
* SYS_DOWN, SYS_HALT, SYS_RESTART, SYS_POWER_OFF
*/
for( i = 0; i < hba_count; i++ ) {
printk(KERN_INFO "megaraid: flushing adapter %d..", i);
host = hba_soft_state[i]->host;
adapter = (adapter_t *)host->hostdata;
mbox = (mbox_t *)raw_mbox;
/* Flush adapter cache */
memset(&mbox->m_out, 0, sizeof(raw_mbox));
raw_mbox[0] = FLUSH_ADAPTER;
irq_disable(adapter);
free_irq(adapter->host->irq, adapter);
/*
* Issue a blocking (interrupts disabled) command to
* the card
*/
issue_scb_block(adapter, raw_mbox);
/* Flush disks cache */
memset(&mbox->m_out, 0, sizeof(raw_mbox));
raw_mbox[0] = FLUSH_SYSTEM;
issue_scb_block(adapter, raw_mbox);
printk("Done.\n");
if( atomic_read(&adapter->pend_cmds) > 0 ) {
printk(KERN_WARNING "megaraid: pending commands!!\n");
}
}
/*
* Have a delibrate delay to make sure all the caches are
* actually flushed.
*/
printk("megaraid: cache flush delay: ");
for( j = 10; j >= 0; j-- ) {
printk("[%d] ", j);
mdelay(1000);
geom[1] = sectors;
geom[2] = cylinders;
}
printk("\n");
return NOTIFY_DONE;
return 0;
}
/**
......@@ -4704,665 +3971,1194 @@ mega_enum_raid_scsi(adapter_t *adapter)
/**
* mega_get_boot_drv()
* mega_get_boot_drv()
* @adapter - pointer to our soft state
*
* Find out which device is the boot device. Note, any logical drive or any
* phyical device (e.g., a CDROM) can be designated as a boot device.
*/
static void
mega_get_boot_drv(adapter_t *adapter)
{
struct private_bios_data *prv_bios_data;
unsigned char raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
u16 cksum = 0;
u8 *cksum_p;
u8 boot_pdrv;
int i;
mbox = (mbox_t *)raw_mbox;
memset(&mbox->m_out, 0, sizeof(raw_mbox));
raw_mbox[0] = BIOS_PVT_DATA;
raw_mbox[2] = GET_BIOS_PVT_DATA;
memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
adapter->boot_ldrv_enabled = 0;
adapter->boot_ldrv = 0;
adapter->boot_pdrv_enabled = 0;
adapter->boot_pdrv_ch = 0;
adapter->boot_pdrv_tgt = 0;
if(issue_scb_block(adapter, raw_mbox) == 0) {
prv_bios_data =
(struct private_bios_data *)adapter->mega_buffer;
cksum = 0;
cksum_p = (char *)prv_bios_data;
for (i = 0; i < 14; i++ ) {
cksum += (u16)(*cksum_p++);
}
if (prv_bios_data->cksum == (u16)(0-cksum) ) {
/*
* If MSB is set, a physical drive is set as boot
* device
*/
if( prv_bios_data->boot_drv & 0x80 ) {
adapter->boot_pdrv_enabled = 1;
boot_pdrv = prv_bios_data->boot_drv & 0x7F;
adapter->boot_pdrv_ch = boot_pdrv / 16;
adapter->boot_pdrv_tgt = boot_pdrv % 16;
}
else {
adapter->boot_ldrv_enabled = 1;
adapter->boot_ldrv = prv_bios_data->boot_drv;
}
}
}
}
/**
* mega_support_random_del()
* @adapter - pointer to our soft state
*
* Find out if this controller supports random deletion and addition of
* logical drives
*/
static int
mega_support_random_del(adapter_t *adapter)
{
unsigned char raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
int rval;
mbox = (mbox_t *)raw_mbox;
memset(&mbox->m_out, 0, sizeof(raw_mbox));
/*
* issue command
*/
raw_mbox[0] = FC_DEL_LOGDRV;
raw_mbox[2] = OP_SUP_DEL_LOGDRV;
rval = issue_scb_block(adapter, raw_mbox);
return !rval;
}
/**
* mega_support_ext_cdb()
* @adapter - pointer to our soft state
*
* Find out if this firmware support cdblen > 10
*/
static int
mega_support_ext_cdb(adapter_t *adapter)
{
unsigned char raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
int rval;
mbox = (mbox_t *)raw_mbox;
memset(&mbox->m_out, 0, sizeof(raw_mbox));
/*
* issue command to find out if controller supports extended CDBs.
*/
raw_mbox[0] = 0xA4;
raw_mbox[2] = 0x16;
rval = issue_scb_block(adapter, raw_mbox);
return !rval;
}
/**
* mega_del_logdrv()
* @adapter - pointer to our soft state
* @logdrv - logical drive to be deleted
*
* Delete the specified logical drive. It is the responsibility of the user
* app to let the OS know about this operation.
*/
static int
mega_del_logdrv(adapter_t *adapter, int logdrv)
{
DECLARE_WAIT_QUEUE_HEAD(wq);
unsigned long flags;
scb_t *scb;
int rval;
/*
* Stop sending commands to the controller, queue them internally.
* When deletion is complete, ISR will flush the queue.
*/
atomic_set(&adapter->quiescent, 1);
/*
* 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 */
}
rval = mega_do_del_logdrv(adapter, logdrv);
spin_lock_irqsave(&adapter->lock, flags);
/*
* If delete operation was successful, add 0x80 to the logical drive
* ids for commands in the pending queue.
*/
if (adapter->read_ldidmap) {
struct list_head *pos;
list_for_each(pos, &adapter->pending_list) {
scb = list_entry(pos, scb_t, list);
if (scb->pthru->logdrv < 0x80 )
scb->pthru->logdrv += 0x80;
}
}
atomic_set(&adapter->quiescent, 0);
mega_runpendq(adapter);
spin_unlock_irqrestore(&adapter->lock, flags);
return rval;
}
static int
mega_do_del_logdrv(adapter_t *adapter, int logdrv)
{
megacmd_t mc;
int rval;
memset( &mc, 0, sizeof(megacmd_t));
mc.cmd = FC_DEL_LOGDRV;
mc.opcode = OP_DEL_LOGDRV;
mc.subopcode = logdrv;
rval = mega_internal_command(adapter, LOCK_INT, &mc, NULL);
/* log this event */
if(rval) {
printk(KERN_WARNING "megaraid: Delete LD-%d failed.", logdrv);
return rval;
}
/*
* After deleting first logical drive, the logical drives must be
* addressed by adding 0x80 to the logical drive id.
*/
adapter->read_ldidmap = 1;
return rval;
}
/**
* mega_get_max_sgl()
* @adapter - pointer to our soft state
*
* Find out the maximum number of scatter-gather elements supported by this
* version of the firmware
*/
static void
mega_get_max_sgl(adapter_t *adapter)
{
unsigned char raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
mbox = (mbox_t *)raw_mbox;
memset(mbox, 0, sizeof(raw_mbox));
memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
raw_mbox[0] = MAIN_MISC_OPCODE;
raw_mbox[2] = GET_MAX_SG_SUPPORT;
if( issue_scb_block(adapter, raw_mbox) ) {
/*
* f/w does not support this command. Choose the default value
*/
adapter->sglen = MIN_SGLIST;
}
else {
adapter->sglen = *((char *)adapter->mega_buffer);
/*
* Make sure this is not more than the resources we are
* planning to allocate
*/
if ( adapter->sglen > MAX_SGLIST )
adapter->sglen = MAX_SGLIST;
}
return;
}
/**
* mega_support_cluster()
* @adapter - pointer to our soft state
*
* Find out which device is the boot device. Note, any logical drive or any
* phyical device (e.g., a CDROM) can be designated as a boot device.
* Find out if this firmware support cluster calls.
*/
static void
mega_get_boot_drv(adapter_t *adapter)
static int
mega_support_cluster(adapter_t *adapter)
{
struct private_bios_data *prv_bios_data;
unsigned char raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
u16 cksum = 0;
u8 *cksum_p;
u8 boot_pdrv;
int i;
mbox = (mbox_t *)raw_mbox;
memset(&mbox->m_out, 0, sizeof(raw_mbox));
raw_mbox[0] = BIOS_PVT_DATA;
raw_mbox[2] = GET_BIOS_PVT_DATA;
memset(mbox, 0, sizeof(raw_mbox));
memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
adapter->boot_ldrv_enabled = 0;
adapter->boot_ldrv = 0;
/*
* Try to get the initiator id. This command will succeed iff the
* clustering is available on this HBA.
*/
raw_mbox[0] = MEGA_GET_TARGET_ID;
adapter->boot_pdrv_enabled = 0;
adapter->boot_pdrv_ch = 0;
adapter->boot_pdrv_tgt = 0;
if( issue_scb_block(adapter, raw_mbox) == 0 ) {
if(issue_scb_block(adapter, raw_mbox) == 0) {
prv_bios_data =
(struct private_bios_data *)adapter->mega_buffer;
/*
* Cluster support available. Get the initiator target id.
* Tell our id to mid-layer too.
*/
adapter->this_id = *(u32 *)adapter->mega_buffer;
adapter->host->this_id = adapter->this_id;
cksum = 0;
cksum_p = (char *)prv_bios_data;
for (i = 0; i < 14; i++ ) {
cksum += (u16)(*cksum_p++);
return 1;
}
if (prv_bios_data->cksum == (u16)(0-cksum) ) {
return 0;
}
/**
* 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 MSB is set, a physical drive is set as boot
* device
* If we have a logical drive with boot enabled, project it first
*/
if( prv_bios_data->boot_drv & 0x80 ) {
adapter->boot_pdrv_enabled = 1;
boot_pdrv = prv_bios_data->boot_drv & 0x7F;
adapter->boot_pdrv_ch = boot_pdrv / 16;
adapter->boot_pdrv_tgt = boot_pdrv % 16;
if( adapter->boot_ldrv_enabled ) {
if( ldrv_num == 0 ) {
ldrv_num = adapter->boot_ldrv;
}
else {
adapter->boot_ldrv_enabled = 1;
adapter->boot_ldrv = prv_bios_data->boot_drv;
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_support_random_del()
* mega_adapinq()
* @adapter - pointer to our soft state
* @dma_handle - DMA address of the buffer
*
* Find out if this controller supports random deletion and addition of
* logical drives
* Issue internal comamnds while interrupts are available.
* We only issue direct mailbox commands from within the driver. ioctl()
* interface using these routines can issue passthru commands.
*/
static int
mega_support_random_del(adapter_t *adapter)
mega_adapinq(adapter_t *adapter, dma_addr_t dma_handle)
{
unsigned char raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
int rval;
megacmd_t mc;
mbox = (mbox_t *)raw_mbox;
memset(&mc, 0, sizeof(megacmd_t));
memset(&mbox->m_out, 0, sizeof(raw_mbox));
if( adapter->flag & BOARD_40LD ) {
mc.cmd = FC_NEW_CONFIG;
mc.opcode = NC_SUBOP_ENQUIRY3;
mc.subopcode = ENQ3_GET_SOLICITED_FULL;
}
else {
mc.cmd = MEGA_MBOXCMD_ADPEXTINQ;
}
/*
* issue command
*/
raw_mbox[0] = FC_DEL_LOGDRV;
raw_mbox[2] = OP_SUP_DEL_LOGDRV;
mc.xferaddr = (u32)dma_handle;
rval = issue_scb_block(adapter, raw_mbox);
if ( mega_internal_command(adapter, LOCK_INT, &mc, NULL) != 0 ) {
return -1;
}
return !rval;
return 0;
}
/**
* mega_support_ext_cdb()
* 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
* @tgt - ID of this device
* @buf_dma_handle - DMA address of the buffer
*
* Find out if this firmware support cdblen > 10
* Issue the scsi inquiry for the specified device.
*/
static int
mega_support_ext_cdb(adapter_t *adapter)
mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt,
dma_addr_t buf_dma_handle)
{
unsigned char raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
mega_passthru *pthru;
dma_addr_t pthru_dma_handle;
megacmd_t mc;
int rval;
struct pci_dev *pdev;
mbox = (mbox_t *)raw_mbox;
memset(&mbox->m_out, 0, sizeof(raw_mbox));
/*
* issue command to find out if controller supports extended CDBs.
* For all internal commands, the buffer must be allocated in <4GB
* address range
*/
raw_mbox[0] = 0xA4;
raw_mbox[2] = 0x16;
if( make_local_pdev(adapter, &pdev) != 0 ) return -1;
rval = issue_scb_block(adapter, raw_mbox);
pthru = pci_alloc_consistent(pdev, sizeof(mega_passthru),
&pthru_dma_handle);
return !rval;
if( pthru == NULL ) {
free_local_pdev(pdev);
return -1;
}
pthru->timeout = 2;
pthru->ars = 1;
pthru->reqsenselen = 14;
pthru->islogical = 0;
pthru->channel = (adapter->flag & BOARD_40LD) ? 0 : ch;
pthru->target = (adapter->flag & BOARD_40LD) ? (ch << 4)|tgt : tgt;
pthru->cdblen = 6;
pthru->cdb[0] = INQUIRY;
pthru->cdb[1] = 0;
pthru->cdb[2] = 0;
pthru->cdb[3] = 0;
pthru->cdb[4] = 255;
pthru->cdb[5] = 0;
pthru->dataxferaddr = (u32)buf_dma_handle;
pthru->dataxferlen = 256;
memset(&mc, 0, sizeof(megacmd_t));
mc.cmd = MEGA_MBOXCMD_PASSTHRU;
mc.xferaddr = (u32)pthru_dma_handle;
rval = mega_internal_command(adapter, LOCK_INT, &mc, pthru);
pci_free_consistent(pdev, sizeof(mega_passthru), pthru,
pthru_dma_handle);
free_local_pdev(pdev);
return rval;
}
/**
* mega_del_logdrv()
* mega_internal_command()
* @adapter - pointer to our soft state
* @logdrv - logical drive to be deleted
* @ls - the scope of the exclusion lock.
* @mc - the mailbox command
* @pthru - Passthru structure for DCDB commands
*
* Delete the specified logical drive. It is the responsibility of the user
* app to let the OS know about this operation.
* Issue the internal commands in interrupt mode.
* The last argument is the address of the passthru structure if the command
* to be fired is a passthru command
*
* lockscope specifies whether the caller has already acquired the lock. Of
* course, the caller must know which lock we are talking about.
*
* Note: parameter 'pthru' is null for non-passthru commands.
*/
static int
mega_del_logdrv(adapter_t *adapter, int logdrv)
mega_internal_command(adapter_t *adapter, lockscope_t ls, megacmd_t *mc,
mega_passthru *pthru )
{
DECLARE_WAIT_QUEUE_HEAD(wq);
unsigned long flags;
Scsi_Cmnd *scmd;
struct scsi_device *sdev;
unsigned long flags = 0;
scb_t *scb;
int rval;
/*
* Stop sending commands to the controller, queue them internally.
* When deletion is complete, ISR will flush the queue.
* 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.
*/
atomic_set(&adapter->quiescent, 1);
down(&adapter->int_mtx);
/*
* 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) ) {
scb = &adapter->int_scb;
memset(scb, 0, sizeof(scb_t));
sleep_on_timeout( &wq, 1*HZ ); /* sleep for 1s */
}
scmd = &adapter->int_scmd;
memset(scmd, 0, sizeof(Scsi_Cmnd));
rval = mega_do_del_logdrv(adapter, logdrv);
sdev = kmalloc(sizeof(struct scsi_device), GFP_KERNEL);
memset(sdev, 0, sizeof(struct scsi_device));
scmd->device = sdev;
spin_lock_irqsave(&adapter->lock, flags);
scmd->device->host = adapter->host;
scmd->buffer = (void *)scb;
scmd->cmnd[0] = MEGA_INTERNAL_CMD;
/*
* If delete operation was successful, add 0x80 to the logical drive
* ids for commands in the pending queue.
*/
if (adapter->read_ldidmap) {
struct list_head *pos;
list_for_each(pos, &adapter->pending_list) {
scb = list_entry(pos, scb_t, list);
if (scb->pthru->logdrv < 0x80 )
scb->pthru->logdrv += 0x80;
}
}
scb->state |= SCB_ACTIVE;
scb->cmd = scmd;
atomic_set(&adapter->quiescent, 0);
memcpy(scb->raw_mbox, mc, sizeof(megacmd_t));
mega_runpendq(adapter);
/*
* Is it a passthru command
*/
if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
spin_unlock_irqrestore(&adapter->lock, flags);
scb->pthru = pthru;
}
return rval;
}
scb->idx = CMDID_INT_CMDS;
scmd->state = 0;
static int
mega_do_del_logdrv(adapter_t *adapter, int logdrv)
{
megacmd_t mc;
int rval;
/*
* Get the lock only if the caller has not acquired it already
*/
if( ls == LOCK_INT ) spin_lock_irqsave(&adapter->lock, flags);
memset( &mc, 0, sizeof(megacmd_t));
megaraid_queue(scmd, mega_internal_done);
mc.cmd = FC_DEL_LOGDRV;
mc.opcode = OP_DEL_LOGDRV;
mc.subopcode = logdrv;
if( ls == LOCK_INT ) spin_unlock_irqrestore(&adapter->lock, flags);
rval = mega_internal_command(adapter, LOCK_INT, &mc, NULL);
/*
* 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);
/* log this event */
if(rval) {
printk(KERN_WARNING "megaraid: Delete LD-%d failed.", logdrv);
return rval;
}
rval = scmd->result;
mc->status = scmd->result;
kfree(sdev);
/*
* After deleting first logical drive, the logical drives must be
* addressed by adding 0x80 to the logical drive id.
* Print a debug message for all failed commands. Applications can use
* this information.
*/
adapter->read_ldidmap = 1;
if( scmd->result && trace_level ) {
printk("megaraid: cmd [%x, %x, %x] status:[%x]\n",
mc->cmd, mc->opcode, mc->subopcode, scmd->result);
}
up(&adapter->int_mtx);
return rval;
}
/**
* mega_get_max_sgl()
* @adapter - pointer to our soft state
* mega_internal_done()
* @scmd - internal scsi command
*
* Find out the maximum number of scatter-gather elements supported by this
* version of the firmware
* Callback routine for internal commands.
*/
static void
mega_get_max_sgl(adapter_t *adapter)
mega_internal_done(Scsi_Cmnd *scmd)
{
unsigned char raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
adapter_t *adapter;
mbox = (mbox_t *)raw_mbox;
adapter = (adapter_t *)scmd->device->host->hostdata;
memset(mbox, 0, sizeof(raw_mbox));
scmd->state = 1; /* thread waiting for its command to complete */
memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
/*
* 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);
mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
}
raw_mbox[0] = MAIN_MISC_OPCODE;
raw_mbox[2] = GET_MAX_SG_SUPPORT;
static inline int
make_local_pdev(adapter_t *adapter, struct pci_dev **pdev)
{
*pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
if( issue_scb_block(adapter, raw_mbox) ) {
/*
* f/w does not support this command. Choose the default value
*/
adapter->sglen = MIN_SGLIST;
}
else {
adapter->sglen = *((char *)adapter->mega_buffer);
if( *pdev == NULL ) return -1;
/*
* Make sure this is not more than the resources we are
* planning to allocate
*/
if ( adapter->sglen > MAX_SGLIST )
adapter->sglen = MAX_SGLIST;
memcpy(*pdev, adapter->dev, sizeof(struct pci_dev));
if( pci_set_dma_mask(*pdev, 0xffffffff) != 0 ) {
kfree(*pdev);
return -1;
}
return;
return 0;
}
/**
* mega_support_cluster()
* @adapter - pointer to our soft state
*
* Find out if this firmware support cluster calls.
*/
static int
mega_support_cluster(adapter_t *adapter)
static inline void
free_local_pdev(struct pci_dev *pdev)
{
unsigned char raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
kfree(pdev);
}
mbox = (mbox_t *)raw_mbox;
static struct scsi_host_template megaraid_template = {
.name = "MegaRAID",
.proc_name = "megaraid",
.info = megaraid_info,
.queuecommand = megaraid_queue,
.bios_param = megaraid_biosparam,
.max_sectors = MAX_SECTORS_PER_IO,
.can_queue = MAX_COMMANDS,
.this_id = DEFAULT_INITIATOR_ID,
.sg_tablesize = MAX_SGLIST,
.cmd_per_lun = DEF_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
.eh_abort_handler = megaraid_abort,
.eh_device_reset_handler = megaraid_reset,
.eh_bus_reset_handler = megaraid_reset,
.eh_host_reset_handler = megaraid_reset,
};
memset(mbox, 0, sizeof(raw_mbox));
static int __devinit
megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct Scsi_Host *host;
adapter_t *adapter;
unsigned long mega_baseport, tbase, flag = 0;
u16 subsysid, subsysvid;
u8 pci_bus, pci_dev_func;
int irq, i, j;
int error = -ENODEV;
memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
if (pci_enable_device(pdev))
goto out;
mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
pci_bus = pdev->bus->number;
pci_dev_func = pdev->devfn;
/*
* Try to get the initiator id. This command will succeed iff the
* clustering is available on this HBA.
* For these vendor and device ids, signature offsets are not
* valid and 64 bit is implicit
*/
raw_mbox[0] = MEGA_GET_TARGET_ID;
if (id->driver_data & BOARD_64BIT)
flag |= BOARD_64BIT;
else {
u32 magic64;
if( issue_scb_block(adapter, raw_mbox) == 0 ) {
pci_read_config_dword(pdev, PCI_CONF_AMISIG64, &magic64);
if (magic64 == HBA_SIGNATURE_64BIT)
flag |= BOARD_64BIT;
}
/*
* Cluster support available. Get the initiator target id.
* Tell our id to mid-layer too.
*/
adapter->this_id = *(u32 *)adapter->mega_buffer;
adapter->host->this_id = adapter->this_id;
subsysvid = pdev->subsystem_vendor;
subsysid = pdev->subsystem_device;
return 1;
printk(KERN_NOTICE "megaraid: found 0x%4.04x:0x%4.04x:bus %d:",
id->vendor, id->device, pci_bus);
printk("slot %d:func %d\n",
PCI_SLOT(pci_dev_func), PCI_FUNC(pci_dev_func));
/* Read the base port and IRQ from PCI */
mega_baseport = pci_resource_start(pdev, 0);
irq = pdev->irq;
tbase = mega_baseport;
if (pci_resource_flags(pdev, 0) & IORESOURCE_MEM) {
flag |= BOARD_MEMMAP;
if (!request_mem_region(mega_baseport, 128, "megaraid")) {
printk(KERN_WARNING "megaraid: mem region busy!\n");
goto out_disable_device;
}
return 0;
}
mega_baseport = (unsigned long)ioremap(mega_baseport, 128);
if (!mega_baseport) {
printk(KERN_WARNING
"megaraid: could not map hba memory\n");
goto out_release_region;
}
} else {
flag |= BOARD_IOMAP;
mega_baseport += 0x10;
if (!request_region(mega_baseport, 16, "megaraid"))
goto out_disable_device;
}
/* Initialize SCSI Host structure */
host = scsi_host_alloc(&megaraid_template, sizeof(adapter_t));
if (!host)
goto out_iounmap;
adapter = (adapter_t *)host->hostdata;
memset(adapter, 0, sizeof(adapter_t));
printk(KERN_NOTICE
"scsi%d:Found MegaRAID controller at 0x%lx, IRQ:%d\n",
host->host_no, mega_baseport, irq);
adapter->base = mega_baseport;
INIT_LIST_HEAD(&adapter->free_list);
INIT_LIST_HEAD(&adapter->pending_list);
INIT_LIST_HEAD(&adapter->completed_list);
adapter->flag = flag;
spin_lock_init(&adapter->lock);
scsi_assign_lock(host, &adapter->lock);
/**
* 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;
host->cmd_per_lun = max_cmd_per_lun;
host->max_sectors = max_sectors_per_io;
tgt = cmd->device->id;
adapter->dev = pdev;
adapter->host = host;
if ( tgt > adapter->this_id )
tgt--; /* we do not get inquires for initiator id */
adapter->host->irq = irq;
ldrv_num = (channel * 15) + tgt;
if (flag & BOARD_MEMMAP)
adapter->host->base = tbase;
else {
adapter->host->io_port = tbase;
adapter->host->n_io_port = 16;
}
adapter->host->unique_id = (pci_bus << 8) | pci_dev_func;
/*
* If we have a logical drive with boot enabled, project it first
* Allocate buffer to issue internal commands.
*/
if( adapter->boot_ldrv_enabled ) {
if( ldrv_num == 0 ) {
ldrv_num = adapter->boot_ldrv;
}
else {
if( ldrv_num <= adapter->boot_ldrv ) {
ldrv_num--;
}
}
adapter->mega_buffer = pci_alloc_consistent(adapter->dev,
MEGA_BUFFER_SIZE, &adapter->buf_dma_handle);
if (!adapter->mega_buffer) {
printk(KERN_WARNING "megaraid: out of RAM.\n");
goto out_host_put;
}
/*
* 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.
*/
adapter->scb_list = kmalloc(sizeof(scb_t) * MAX_COMMANDS, GFP_KERNEL);
if (!adapter->scb_list) {
printk(KERN_WARNING "megaraid: out of RAM.\n");
goto out_free_cmd_buffer;
}
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;
if (request_irq(irq, (adapter->flag & BOARD_MEMMAP) ?
megaraid_isr_memmapped : megaraid_isr_iomapped,
SA_SHIRQ, "megaraid", adapter)) {
printk(KERN_WARNING
"megaraid: Couldn't register IRQ %d!\n", irq);
goto out_free_scb_list;
}
return ldrv_num;
}
if (mega_setup_mailbox(adapter))
goto out_free_irq;
if (mega_query_adapter(adapter))
goto out_free_mbox;
/**
* mega_adapinq()
* @adapter - pointer to our soft state
* @dma_handle - DMA address of the buffer
*
* Issue internal comamnds while interrupts are available.
* We only issue direct mailbox commands from within the driver. ioctl()
* interface using these routines can issue passthru commands.
/*
* Have checks for some buggy f/w
*/
static int
mega_adapinq(adapter_t *adapter, dma_addr_t dma_handle)
{
megacmd_t mc;
memset(&mc, 0, sizeof(megacmd_t));
if ((subsysid == 0x1111) && (subsysvid == 0x1111)) {
/*
* Which firmware
*/
if (!strcmp(adapter->fw_version, "3.00") ||
!strcmp(adapter->fw_version, "3.01")) {
if( adapter->flag & BOARD_40LD ) {
mc.cmd = FC_NEW_CONFIG;
mc.opcode = NC_SUBOP_ENQUIRY3;
mc.subopcode = ENQ3_GET_SOLICITED_FULL;
printk( KERN_WARNING
"megaraid: Your card is a Dell PERC "
"2/SC RAID controller with "
"firmware\nmegaraid: 3.00 or 3.01. "
"This driver is known to have "
"corruption issues\nmegaraid: with "
"those firmware versions on this "
"specific card. In order\nmegaraid: "
"to protect your data, please upgrade "
"your firmware to version\nmegaraid: "
"3.10 or later, available from the "
"Dell Technical Support web\n"
"megaraid: site at\nhttp://support."
"dell.com/us/en/filelib/download/"
"index.asp?fileid=2940\n"
);
}
else {
mc.cmd = MEGA_MBOXCMD_ADPEXTINQ;
}
mc.xferaddr = (u32)dma_handle;
if ( mega_internal_command(adapter, LOCK_INT, &mc, NULL) != 0 ) {
return -1;
/*
* If we have a HP 1M(0x60E7)/2M(0x60E8) controller with
* firmware H.01.07, H.01.08, and H.01.09 disable 64 bit
* support, since this firmware cannot handle 64 bit
* addressing
*/
if ((subsysvid == HP_SUBSYS_VID) &&
((subsysid == 0x60E7) || (subsysid == 0x60E8))) {
/*
* which firmware
*/
if (!strcmp(adapter->fw_version, "H01.07") ||
!strcmp(adapter->fw_version, "H01.08") ||
!strcmp(adapter->fw_version, "H01.09") ) {
printk(KERN_WARNING
"megaraid: Firmware H.01.07, "
"H.01.08, and H.01.09 on 1M/2M "
"controllers\n"
"megaraid: do not support 64 bit "
"addressing.\nmegaraid: DISABLING "
"64 bit support.\n");
adapter->flag &= ~BOARD_64BIT;
}
}
return 0;
}
if (mega_is_bios_enabled(adapter))
mega_hbas[hba_count].is_bios_enabled = 1;
mega_hbas[hba_count].hostdata_addr = adapter;
/**
* mega_allocate_inquiry()
* @dma_handle - handle returned for dma address
* @pdev - handle to pci device
*
* allocates memory for inquiry structure
/*
* Find out which channel is raid and which is scsi. This is
* for ROMB support.
*/
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);
}
mega_enum_raid_scsi(adapter);
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);
}
/*
* Find out if a logical drive is set as the boot drive. If
* there is one, will make that as the first logical drive.
* ROMB: Do we have to boot from a physical drive. Then all
* the physical drives would appear before the logical disks.
* Else, all the physical drives would be exported to the mid
* layer after logical drives.
*/
mega_get_boot_drv(adapter);
if (adapter->boot_pdrv_enabled) {
j = adapter->product_info.nchannels;
for( i = 0; i < j; i++ )
adapter->logdrv_chan[i] = 0;
for( i = j; i < NVIRT_CHAN + j; i++ )
adapter->logdrv_chan[i] = 1;
} else {
for (i = 0; i < NVIRT_CHAN; i++)
adapter->logdrv_chan[i] = 1;
for (i = NVIRT_CHAN; i < MAX_CHANNELS+NVIRT_CHAN; i++)
adapter->logdrv_chan[i] = 0;
adapter->mega_ch_class <<= NVIRT_CHAN;
}
/** mega_internal_dev_inquiry()
* @adapter - pointer to our soft state
* @ch - channel for this device
* @tgt - ID of this device
* @buf_dma_handle - DMA address of the buffer
*
* Issue the scsi inquiry for the specified device.
/*
* Do we support random deletion and addition of logical
* drives
*/
static int
mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt,
dma_addr_t buf_dma_handle)
{
mega_passthru *pthru;
dma_addr_t pthru_dma_handle;
megacmd_t mc;
int rval;
struct pci_dev *pdev;
adapter->read_ldidmap = 0; /* set it after first logdrv
delete cmd */
adapter->support_random_del = mega_support_random_del(adapter);
/* Initialize SCBs */
if (mega_init_scb(adapter))
goto out_free_mbox;
/*
* For all internal commands, the buffer must be allocated in <4GB
* address range
* Reset the pending commands counter
*/
if( make_local_pdev(adapter, &pdev) != 0 ) return -1;
pthru = pci_alloc_consistent(pdev, sizeof(mega_passthru),
&pthru_dma_handle);
atomic_set(&adapter->pend_cmds, 0);
if( pthru == NULL ) {
free_local_pdev(pdev);
return -1;
}
/*
* Reset the adapter quiescent flag
*/
atomic_set(&adapter->quiescent, 0);
pthru->timeout = 2;
pthru->ars = 1;
pthru->reqsenselen = 14;
pthru->islogical = 0;
hba_soft_state[hba_count] = adapter;
pthru->channel = (adapter->flag & BOARD_40LD) ? 0 : ch;
/*
* Fill in the structure which needs to be passed back to the
* application when it does an ioctl() for controller related
* information.
*/
i = hba_count;
pthru->target = (adapter->flag & BOARD_40LD) ? (ch << 4)|tgt : tgt;
mcontroller[i].base = mega_baseport;
mcontroller[i].irq = irq;
mcontroller[i].numldrv = adapter->numldrv;
mcontroller[i].pcibus = pci_bus;
mcontroller[i].pcidev = id->device;
mcontroller[i].pcifun = PCI_FUNC (pci_dev_func);
mcontroller[i].pciid = -1;
mcontroller[i].pcivendor = id->vendor;
mcontroller[i].pcislot = PCI_SLOT(pci_dev_func);
mcontroller[i].uid = (pci_bus << 8) | pci_dev_func;
pthru->cdblen = 6;
pthru->cdb[0] = INQUIRY;
pthru->cdb[1] = 0;
pthru->cdb[2] = 0;
pthru->cdb[3] = 0;
pthru->cdb[4] = 255;
pthru->cdb[5] = 0;
/* 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);
adapter->has_64bit_addr = 1;
} else {
pci_set_dma_mask(pdev, 0xffffffff);
adapter->has_64bit_addr = 0;
}
init_MUTEX(&adapter->int_mtx);
init_waitqueue_head(&adapter->int_waitq);
pthru->dataxferaddr = (u32)buf_dma_handle;
pthru->dataxferlen = 256;
adapter->this_id = DEFAULT_INITIATOR_ID;
adapter->host->this_id = DEFAULT_INITIATOR_ID;
memset(&mc, 0, sizeof(megacmd_t));
#if MEGA_HAVE_CLUSTERING
/*
* Is cluster support enabled on this controller
* Note: In a cluster the HBAs ( the initiators ) will have
* different target IDs and we cannot assume it to be 7. Call
* to mega_support_cluster() will get the target ids also if
* the cluster support is available
*/
adapter->has_cluster = mega_support_cluster(adapter);
if (adapter->has_cluster) {
printk(KERN_NOTICE
"megaraid: Cluster driver, initiator id:%d\n",
adapter->this_id);
}
#endif
mc.cmd = MEGA_MBOXCMD_PASSTHRU;
mc.xferaddr = (u32)pthru_dma_handle;
pci_set_drvdata(pdev, host);
rval = mega_internal_command(adapter, LOCK_INT, &mc, pthru);
mega_create_proc_entry(hba_count, mega_proc_dir_entry);
pci_free_consistent(pdev, sizeof(mega_passthru), pthru,
pthru_dma_handle);
error = scsi_add_host(host, &pdev->dev);
if (error)
goto out_free_mbox;
free_local_pdev(pdev);
scsi_scan_host(host);
hba_count++;
return 0;
return rval;
out_free_mbox:
pci_free_consistent(adapter->dev, sizeof(mbox64_t),
adapter->una_mbox64, adapter->una_mbox64_dma);
out_free_irq:
free_irq(adapter->host->irq, adapter);
out_free_scb_list:
kfree(adapter->scb_list);
out_free_cmd_buffer:
pci_free_consistent(adapter->dev, MEGA_BUFFER_SIZE,
adapter->mega_buffer, adapter->buf_dma_handle);
out_host_put:
scsi_host_put(host);
out_iounmap:
if (flag & BOARD_MEMMAP)
iounmap((void *)mega_baseport);
out_release_region:
if (flag & BOARD_MEMMAP)
release_mem_region(tbase, 128);
else
release_region(mega_baseport, 16);
out_disable_device:
pci_disable_device(pdev);
out:
return error;
}
/**
* 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
*
* Issue the internal commands in interrupt mode.
* The last argument is the address of the passthru structure if the command
* to be fired is a passthru command
*
* lockscope specifies whether the caller has already acquired the lock. Of
* course, the caller must know which lock we are talking about.
*
* 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 )
static void
__megaraid_shutdown(adapter_t *adapter)
{
Scsi_Cmnd *scmd;
struct scsi_device *sdev;
unsigned long flags = 0;
scb_t *scb;
int rval;
/*
* 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);
u_char raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox = (mbox_t *)raw_mbox;
int i;
scb = &adapter->int_scb;
memset(scb, 0, sizeof(scb_t));
/* Flush adapter cache */
memset(&mbox->m_out, 0, sizeof(raw_mbox));
raw_mbox[0] = FLUSH_ADAPTER;
scmd = &adapter->int_scmd;
memset(scmd, 0, sizeof(Scsi_Cmnd));
free_irq(adapter->host->irq, adapter);
sdev = kmalloc(sizeof(struct scsi_device), GFP_KERNEL);
memset(sdev, 0, sizeof(struct scsi_device));
scmd->device = sdev;
/* Issue a blocking (interrupts disabled) command to the card */
issue_scb_block(adapter, raw_mbox);
scmd->device->host = adapter->host;
scmd->buffer = (void *)scb;
scmd->cmnd[0] = MEGA_INTERNAL_CMD;
/* Flush disks cache */
memset(&mbox->m_out, 0, sizeof(raw_mbox));
raw_mbox[0] = FLUSH_SYSTEM;
scb->state |= SCB_ACTIVE;
scb->cmd = scmd;
/* Issue a blocking (interrupts disabled) command to the card */
issue_scb_block(adapter, raw_mbox);
memcpy(scb->raw_mbox, mc, sizeof(megacmd_t));
if (atomic_read(&adapter->pend_cmds) > 0)
printk(KERN_WARNING "megaraid: pending commands!!\n");
/*
* Is it a passthru command
* Have a delibrate delay to make sure all the caches are
* actually flushed.
*/
if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
scb->pthru = pthru;
}
for (i = 0; i <= 10; i++)
mdelay(1000);
}
scb->idx = CMDID_INT_CMDS;
static void
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 };
scmd->state = 0;
scsi_remove_host(host);
/*
* Get the lock only if the caller has not acquired it already
*/
if( ls == LOCK_INT ) spin_lock_irqsave(&adapter->lock, flags);
__megaraid_shutdown(adapter);
megaraid_queue(scmd, mega_internal_done);
/* Free our resources */
if (adapter->flag & BOARD_MEMMAP) {
iounmap((void *)adapter->base);
release_mem_region(adapter->host->base, 128);
} else
release_region(adapter->base, 16);
if( ls == LOCK_INT ) spin_unlock_irqrestore(&adapter->lock, flags);
mega_free_sgl(adapter);
/*
* 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);
#ifdef CONFIG_PROC_FS
if (adapter->controller_proc_dir_entry) {
remove_proc_entry("stat", adapter->controller_proc_dir_entry);
remove_proc_entry("config",
adapter->controller_proc_dir_entry);
remove_proc_entry("mailbox",
adapter->controller_proc_dir_entry);
#if MEGA_HAVE_ENH_PROC
remove_proc_entry("rebuild-rate",
adapter->controller_proc_dir_entry);
remove_proc_entry("battery-status",
adapter->controller_proc_dir_entry);
rval = scmd->result;
mc->status = scmd->result;
kfree(sdev);
remove_proc_entry("diskdrives-ch0",
adapter->controller_proc_dir_entry);
remove_proc_entry("diskdrives-ch1",
adapter->controller_proc_dir_entry);
remove_proc_entry("diskdrives-ch2",
adapter->controller_proc_dir_entry);
remove_proc_entry("diskdrives-ch3",
adapter->controller_proc_dir_entry);
/*
* Print a debug message for all failed commands. Applications can use
* this information.
*/
if( scmd->result && trace_level ) {
printk("megaraid: cmd [%x, %x, %x] status:[%x]\n",
mc->cmd, mc->opcode, mc->subopcode, scmd->result);
remove_proc_entry("raiddrives-0-9",
adapter->controller_proc_dir_entry);
remove_proc_entry("raiddrives-10-19",
adapter->controller_proc_dir_entry);
remove_proc_entry("raiddrives-20-29",
adapter->controller_proc_dir_entry);
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);
}
#endif
up(&adapter->int_mtx);
pci_free_consistent(adapter->dev, MEGA_BUFFER_SIZE,
adapter->mega_buffer, adapter->buf_dma_handle);
kfree(adapter->scb_list);
pci_free_consistent(adapter->dev, sizeof(mbox64_t),
adapter->una_mbox64, adapter->una_mbox64_dma);
return rval;
}
scsi_host_put(host);
pci_disable_device(pdev);
hba_count--;
}
/**
* mega_internal_done()
* @scmd - internal scsi command
*
* Callback routine for internal commands.
*/
static void
mega_internal_done(Scsi_Cmnd *scmd)
megaraid_shutdown(struct device *dev)
{
adapter_t *adapter;
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);
struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
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_MEGARAID,
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",
.id_table = megaraid_pci_tbl,
.probe = megaraid_probe_one,
.remove = __devexit_p(megaraid_remove_one),
.driver = {
.shutdown = megaraid_shutdown,
},
};
static inline int
make_local_pdev(adapter_t *adapter, struct pci_dev **pdev)
static int __init megaraid_init(void)
{
*pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
int error;
if( *pdev == NULL ) return -1;
if ((max_cmd_per_lun <= 0) || (max_cmd_per_lun > MAX_CMD_PER_LUN))
max_cmd_per_lun = MAX_CMD_PER_LUN;
if (max_mbox_busy_wait > MBOX_BUSY_WAIT)
max_mbox_busy_wait = MBOX_BUSY_WAIT;
memcpy(*pdev, adapter->dev, sizeof(struct pci_dev));
error = pci_module_init(&megaraid_pci_driver);
if (error)
return error;
if( pci_set_dma_mask(*pdev, 0xffffffff) != 0 ) {
kfree(*pdev);
return -1;
#ifdef CONFIG_PROC_FS
mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root);
if (!mega_proc_dir_entry) {
printk(KERN_WARNING
"megaraid: failed to create megaraid root\n");
}
#endif
/*
* Register the driver as a character device, for applications
* to access it for ioctls.
* First argument (major) to register_chrdev implies a dynamic
* major number allocation.
*/
major = register_chrdev(0, "megadev", &megadev_fops);
if (!major) {
printk(KERN_WARNING
"megaraid: failed to register char device\n");
}
return 0;
}
static inline void
free_local_pdev(struct pci_dev *pdev)
static void __exit megaraid_exit(void)
{
kfree(pdev);
/*
* Unregister the character device interface to the driver.
*/
unregister_chrdev(major, "megadev");
#ifdef CONFIG_PROC_FS
remove_proc_entry("megaraid", &proc_root);
#endif
pci_unregister_driver(&megaraid_pci_driver);
}
static Scsi_Host_Template driver_template = {
.name = "MegaRAID",
.detect = megaraid_detect,
.release = megaraid_release,
.info = megaraid_info,
.queuecommand = megaraid_queue,
.bios_param = megaraid_biosparam,
.max_sectors = MAX_SECTORS_PER_IO,
.can_queue = MAX_COMMANDS,
.this_id = DEFAULT_INITIATOR_ID,
.sg_tablesize = MAX_SGLIST,
.cmd_per_lun = DEF_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
.eh_abort_handler = megaraid_abort,
.eh_device_reset_handler = megaraid_reset,
.eh_bus_reset_handler = megaraid_reset,
.eh_host_reset_handler = megaraid_reset,
};
#include "scsi_module.c"
module_init(megaraid_init);
module_exit(megaraid_exit);
/* vi: set ts=8 sw=8 tw=78: */
......@@ -989,8 +989,6 @@ typedef enum { LOCK_INT, LOCK_EXT } lockscope_t;
const char *megaraid_info (struct Scsi_Host *);
static int megaraid_detect(Scsi_Host_Template *);
static void mega_find_card(Scsi_Host_Template *, u16, u16);
static int mega_query_adapter(adapter_t *);
static inline int issue_scb(adapter_t *, scb_t *);
static int mega_setup_mailbox(adapter_t *);
......@@ -1007,7 +1005,6 @@ static irqreturn_t megaraid_isr_iomapped(int, void *, struct pt_regs *);
static void mega_free_scb(adapter_t *, scb_t *);
static int megaraid_release (struct Scsi_Host *);
static int megaraid_abort(Scsi_Cmnd *);
static int megaraid_reset(Scsi_Cmnd *);
static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int);
......@@ -1025,8 +1022,6 @@ static inline void mega_free_sgl (adapter_t *adapter);
static void mega_8_to_40ld (mraid_inquiry *inquiry,
mega_inquiry3 *enquiry3, mega_product_info *);
static int megaraid_reboot_notify (struct notifier_block *,
unsigned long, void *);
static int megadev_open (struct inode *, struct file *);
static int megadev_ioctl (struct inode *, struct file *, unsigned int,
unsigned long);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment