patch-2.3.15 linux/drivers/scsi/megaraid.c
Next file: linux/drivers/scsi/megaraid.h
Previous file: linux/drivers/scsi/mca_53c9x.c
Back to the patch index
Back to the overall index
- Lines: 1065
- Date:
Mon Aug 23 13:44:03 1999
- Orig file:
v2.3.14/linux/drivers/scsi/megaraid.c
- Orig date:
Mon Aug 9 10:25:01 1999
diff -u --recursive --new-file v2.3.14/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
@@ -9,14 +9,12 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version : 1.00
+ * Version : 1.04
*
* Description: Linux device driver for AMI MegaRAID controller
*
- * Supported controllers: MegaRAID 418, 428, 438, 466, 762
+ * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 490
*
- * Maintainer: Jeff L Jones <jeffreyj@ami.com>
- *
* History:
*
* Version 0.90:
@@ -38,10 +36,10 @@
* Removed setting of SA_INTERRUPT flag when requesting Irq.
*
* Version 0.92ac:
- * Small changes to the comments/formatting. Plus a couple of
+ * Small changes to the comments/formatting. Plus a couple of
* added notes. Returned to the authors. No actual code changes
* save printk levels.
- * 8 Oct 98 Alan Cox <alan.cox@linux.org>
+ * 8 Oct 98 Alan Cox <alan.cox@linux.org>
*
* Merged with 2.1.131 source tree.
* 12 Dec 98 K. Baranowski <kgb@knm.org.pl>
@@ -73,14 +71,15 @@
*
* Version 0.96:
* 762 fully supported.
+ *
* Version 0.97:
* Changed megaraid_command to use wait_queue.
* Fixed bug of undesirably detecting HP onboard controllers which
- * are disabled.
+ * are disabled.
*
* Version 1.00:
* Checks to see if an irq ocurred while in isr, and runs through
- * routine again.
+ * routine again.
* Copies mailbox to temp area before processing in isr
* Added barrier() in busy wait to fix volatility bug
* Uses separate list for freed Scbs, keeps track of cmd state
@@ -88,17 +87,45 @@
* Full multi-io commands working stablely without previous problems
* Added skipXX LILO option for Madrona motherboard support
*
+ * Version 1.01:
+ * Fixed bug in mega_cmd_done() for megamgr control commands,
+ * the host_byte in the result code from the scsi request to
+ * scsi midlayer is set to DID_BAD_TARGET when adapter's
+ * returned codes are 0xF0 and 0xF4.
+ *
+ * Version 1.02:
+ * Fixed the tape drive bug by extending the adapter timeout value
+ * for passthrough command to 60 seconds in mega_build_cmd().
+ *
+ * Version 1.03:
+ * Fixed Madrona support.
+ * Changed the adapter timeout value from 60 sec in 1.02 to 10 min
+ * for bigger and slower tape drive.
+ * Added driver version printout at driver loadup time
+ *
+ * Version 1.04
+ * Added code for 40 ld FW support.
+ * Added new ioctl command 0x81 to support NEW_READ/WRITE_CONFIG with
+ * data area greater than 4 KB, which is the upper bound for data
+ * tranfer through scsi_ioctl interface.
+ * The addtional 32 bit field for 64bit address in the newly defined
+ * mailbox64 structure is set to 0 at this point.
*
* BUGS:
* Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
* fails to detect the controller as a pci device on the system.
*
- * Timeout period for mid scsi layer is too short for
- * this controller. Must be increased or Aborts will occur.
+ * Timeout period for upper scsi layer, i.e. SD_TIMEOUT in
+ * /drivers/scsi/sd.c, is too short for this controller. SD_TIMEOUT
+ * value must be increased to (30 * HZ) otherwise false timeouts
+ * will occur in the upper layer.
*
*===================================================================*/
#define CRLFSTR "\n"
+#define IOCTL_CMD_NEW 0x81
+
+#define MEGARAID_VERSION "v1.04 (August 16, 1999)"
#include <linux/version.h>
@@ -138,6 +165,7 @@
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/uaccess.h>
#include "sd.h"
#include "scsi.h"
@@ -203,22 +231,22 @@
spin_unlock_irqrestore(&mega_lock,cpuflag);\
};
-u_long RDINDOOR (mega_host_config * megaCfg)
+u32 RDINDOOR (mega_host_config * megaCfg)
{
return readl (megaCfg->base + 0x20);
}
-void WRINDOOR (mega_host_config * megaCfg, u_long value)
+void WRINDOOR (mega_host_config * megaCfg, u32 value)
{
writel (value, megaCfg->base + 0x20);
}
-u_long RDOUTDOOR (mega_host_config * megaCfg)
+u32 RDOUTDOOR (mega_host_config * megaCfg)
{
return readl (megaCfg->base + 0x2C);
}
-void WROUTDOOR (mega_host_config * megaCfg, u_long value)
+void WROUTDOOR (mega_host_config * megaCfg, u32 value)
{
writel (value, megaCfg->base + 0x2C);
}
@@ -234,7 +262,7 @@
mega_scb * scb,
int intr);
static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
- u_long * buffer, u_long * length);
+ u32 * buffer, u32 * length);
static int mega_busyWaitMbox(mega_host_config *);
static void mega_runpendq (mega_host_config *);
@@ -242,6 +270,9 @@
static void mega_cmd_done (mega_host_config *, mega_scb *, int);
static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);
static inline void freeSgList(mega_host_config *megaCfg);
+static void mega_Convert8ldTo40ld( mega_RAIDINQ *inquiry,
+ mega_Enquiry3 *enquiry3,
+ megaRaidProductInfo *productInfo );
/* set SERDEBUG to 1 to enable serial debugging */
#define SERDEBUG 0
@@ -259,9 +290,9 @@
*================================================================
*/
-/* Use "megaraid=skipXX" to prohibit driver from scanning XX scsi id
- on each channel. Used for Madrona motherboard, where SAF_TE
- processor id cannot be scanned */
+/* Use "megaraid=skipXX" as LILO option to prohibit driver from scanning
+ XX scsi id on each channel. Used for Madrona motherboard, where SAF_TE
+ processor id cannot be scanned */
static char *megaraid;
#if LINUX_VERSION_CODE > 0x20100
#ifdef MODULE
@@ -271,10 +302,10 @@
static int skip_id;
static int numCtlrs = 0;
-static mega_host_config *megaCtlrs[12] = {0};
+static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = {0};
#if DEBUG
-static u_long maxCmdTime = 0;
+static u32 maxCmdTime = 0;
#endif
static mega_scb *pLastScb = NULL;
@@ -480,6 +511,8 @@
{
int islogical;
Scsi_Cmnd *SCpnt;
+ mega_passthru *pthru;
+ mega_mailbox *mbox;
if (pScb == NULL) {
TRACE(("NULL pScb in mega_cmd_done!"));
@@ -487,7 +520,9 @@
}
SCpnt = pScb->SCpnt;
- freeSCB(megaCfg, pScb);
+ /*freeSCB(megaCfg, pScb);*/ /*delay this to the end of this func.*/
+ pthru = &pScb->pthru;
+ mbox = (mega_mailbox *) &pScb->mboxData;
if (SCpnt == NULL) {
TRACE(("NULL SCpnt in mega_cmd_done!"));
@@ -498,30 +533,58 @@
while(1);
}
- islogical = (SCpnt->channel == megaCfg->host->max_channel &&
- SCpnt->target == 0);
+ islogical = (SCpnt->channel == megaCfg->host->max_channel);
+
if (SCpnt->cmnd[0] == INQUIRY &&
((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&
!islogical) {
status = 0xF0;
}
-
- SCpnt->result = 0; /* clear result; otherwise, success returns corrupt
- value */
+/* clear result; otherwise, success returns corrupt value */
+ SCpnt->result = 0;
+
+if ((SCpnt->cmnd[0] & 0x80) ) {/* i.e. ioctl cmd such as 0x80, 0x81 of megamgr*/
+ switch (status) {
+ case 0xF0:
+ case 0xF4:
+ SCpnt->result=(DID_BAD_TARGET<<16)|status;
+ break;
+ default:
+ SCpnt->result|=status;
+ }/*end of switch*/
+}
+else{
/* Convert MegaRAID status to Linux error code */
switch (status) {
- case 0x00: /* SUCCESS */
- case 0x02: /* ERROR_ABORTED */
+ case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD*/
SCpnt->result |= (DID_OK << 16);
break;
- case 0x8: /* ERR_DEST_DRIVE_FAILED */
- SCpnt->result |= (DID_BUS_BUSY << 16);
+ case 0x02: /* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */
+ /*set sense_buffer and result fields*/
+ if( mbox->cmd==MEGA_MBOXCMD_PASSTHRU ){
+ memcpy( SCpnt->sense_buffer , pthru->reqsensearea, 14);
+ SCpnt->result = (DRIVER_SENSE<<24)|(DID_ERROR << 16)|status;
+ }
+ else{
+ SCpnt->sense_buffer[0]=0x70;
+ SCpnt->sense_buffer[2]=ABORTED_COMMAND;
+ SCpnt->result |= (CHECK_CONDITION << 1);
+ }
break;
- default:
- SCpnt->result |= (DID_BAD_TARGET << 16);
+ case 0x08: /* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */
+ SCpnt->result |= (DID_BUS_BUSY << 16)|status;
+ break;
+ default:
+ SCpnt->result |= (DID_BAD_TARGET << 16)|status;
break;
}
+ }
+ if ( SCpnt->cmnd[0]!=IOCTL_CMD_NEW )
+ /* not IOCTL_CMD_NEW SCB, freeSCB()*/
+ /* For IOCTL_CMD_NEW SCB, delay freeSCB() in megaraid_queue()
+ * after copy data back to user space*/
+ freeSCB(megaCfg, pScb);
/* Add Scsi_Command to end of completed queue */
ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
@@ -543,18 +606,14 @@
mega_passthru *pthru;
long seg;
char islogical;
+ char lun = SCpnt->lun;
- if (SCpnt == NULL) {
- printk("NULL SCpnt in mega_build_cmd!\n");
- while(1);
- }
-
- if (SCpnt->cmnd[0] & 0x80) /* ioctl from megamgr */
+ if ((SCpnt->cmnd[0] == 0x80) || (SCpnt->cmnd[0] == IOCTL_CMD_NEW) ) /* ioctl */
return mega_ioctl (megaCfg, SCpnt);
+
+ islogical = (SCpnt->channel == megaCfg->host->max_channel);
- islogical = (SCpnt->channel == megaCfg->host->max_channel && SCpnt->target == 0);
-
- if (!islogical && SCpnt->lun != 0) {
+ if (!islogical && lun != 0) {
SCpnt->result = (DID_BAD_TARGET << 16);
callDone (SCpnt);
return NULL;
@@ -566,6 +625,16 @@
return NULL;
}
+ if ( islogical ) {
+ lun = (SCpnt->target * 8) + lun;
+#if 1
+ if ( lun > FC_MAX_LOGICAL_DRIVES ){
+ SCpnt->result = (DID_BAD_TARGET << 16);
+ callDone (SCpnt);
+ return NULL;
+ }
+#endif
+ }
/*-----------------------------------------------------
*
* Logical drive commands
@@ -602,7 +671,7 @@
pthru->ars = 1;
pthru->reqsenselen = 14;
pthru->islogical = 1;
- pthru->logdrv = SCpnt->lun;
+ pthru->logdrv = lun;
pthru->cdblen = SCpnt->cmd_len;
pthru->dataxferaddr = virt_to_bus (SCpnt->request_buffer);
pthru->dataxferlen = SCpnt->request_bufflen;
@@ -627,37 +696,37 @@
mbox = (mega_mailbox *) & pScb->mboxData;
memset (mbox, 0, sizeof (pScb->mboxData));
- mbox->logdrv = SCpnt->lun;
+ mbox->logdrv = lun;
mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ?
MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE;
/* 6-byte */
if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) {
mbox->numsectors =
- (u_long) SCpnt->cmnd[4];
+ (u32) SCpnt->cmnd[4];
mbox->lba =
- ((u_long) SCpnt->cmnd[1] << 16) |
- ((u_long) SCpnt->cmnd[2] << 8) |
- (u_long) SCpnt->cmnd[3];
+ ((u32) SCpnt->cmnd[1] << 16) |
+ ((u32) SCpnt->cmnd[2] << 8) |
+ (u32) SCpnt->cmnd[3];
mbox->lba &= 0x1FFFFF;
}
/* 10-byte */
if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {
mbox->numsectors =
- (u_long) SCpnt->cmnd[8] |
- ((u_long) SCpnt->cmnd[7] << 8);
+ (u32) SCpnt->cmnd[8] |
+ ((u32) SCpnt->cmnd[7] << 8);
mbox->lba =
- ((u_long) SCpnt->cmnd[2] << 24) |
- ((u_long) SCpnt->cmnd[3] << 16) |
- ((u_long) SCpnt->cmnd[4] << 8) |
- (u_long) SCpnt->cmnd[5];
+ ((u32) SCpnt->cmnd[2] << 24) |
+ ((u32) SCpnt->cmnd[3] << 16) |
+ ((u32) SCpnt->cmnd[4] << 8) |
+ (u32) SCpnt->cmnd[5];
}
/* Calculate Scatter-Gather info */
mbox->numsgelements = build_sglist (megaCfg, pScb,
- (u_long *) & mbox->xferaddr,
- (u_long *) & seg);
+ (u32 *) & mbox->xferaddr,
+ (u32 *) & seg);
return pScb;
@@ -684,18 +753,20 @@
memset (mbox, 0, sizeof (pScb->mboxData));
memset (pthru, 0, sizeof (mega_passthru));
- pthru->timeout = 0;
+ pthru->timeout = 2; /*set adapter timeout value to 10 min. for tape drive*/
+ /* 0=6sec/1=60sec/2=10min/3=3hrs */
pthru->ars = 1;
pthru->reqsenselen = 14;
pthru->islogical = 0;
- pthru->channel = SCpnt->channel;
- pthru->target = SCpnt->target;
+ pthru->channel = (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel;
+ pthru->target = (megaCfg->flag & BOARD_40LD) ? /*BOARD_40LD*/
+ (SCpnt->channel<<4)|SCpnt->target : SCpnt->target;
pthru->cdblen = SCpnt->cmd_len;
memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
pthru->numsgelements = build_sglist (megaCfg, pScb,
- (u_long *) & pthru->dataxferaddr,
- (u_long *) & pthru->dataxferlen);
+ (u32 *) & pthru->dataxferaddr,
+ (u32 *) & pthru->dataxferlen);
/* Initialize mailbox */
mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
@@ -715,6 +786,7 @@
mega_ioctl_mbox *mbox;
mega_mailbox *mailbox;
mega_passthru *pthru;
+ u8 *mboxdata;
long seg;
unsigned char *data = (unsigned char *)SCpnt->request_buffer;
int i;
@@ -733,13 +805,13 @@
printk("......\n");
#endif
+ mboxdata = (u8 *) & pScb->mboxData;
mbox = (mega_ioctl_mbox *) & pScb->mboxData;
mailbox = (mega_mailbox *) & pScb->mboxData;
memset (mailbox, 0, sizeof (pScb->mboxData));
if (data[0] == 0x03) { /* passthrough command */
unsigned char cdblen = data[2];
-
pthru = &pScb->pthru;
memset (pthru, 0, sizeof (mega_passthru));
pthru->islogical = (data[cdblen+3] & 0x80) ? 1:0;
@@ -755,10 +827,9 @@
mailbox->cmd = MEGA_MBOXCMD_PASSTHRU;
mailbox->xferaddr = virt_to_bus (pthru);
-
pthru->numsgelements = build_sglist (megaCfg, pScb,
- (u_long *) & pthru->dataxferaddr,
- (u_long *) & pthru->dataxferlen);
+ (u32 *) & pthru->dataxferaddr,
+ (u32 *) & pthru->dataxferlen);
for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) {
data[i] = data[i+cdblen+7];
@@ -768,18 +839,60 @@
}
/* else normal (nonpassthru) command */
+ if (SCpnt->cmnd[0] == IOCTL_CMD_NEW) {
+ /* use external data area for large xfers */
+ /* If cmnd[0] is set to IOCTL_CMD_NEW then *
+ * cmnd[4..7] = external user buffer *
+ * cmnd[8..11] = length of buffer *
+ * */
+ char *kern_area;
+ char *user_area = *((char **)&SCpnt->cmnd[4]);
+ u32 xfer_size = *((u32 *)&SCpnt->cmnd[8]);
+ if (verify_area(VERIFY_READ, user_area, xfer_size)) {
+ printk("megaraid: Got bad user address.\n");
+ SCpnt->result = (DID_ERROR << 16);
+ callDone (SCpnt);
+ return NULL;
+ }
+ kern_area = kmalloc(xfer_size, GFP_ATOMIC | GFP_DMA);
+ if (kern_area == NULL) {
+ printk("megaraid: Couldn't allocate kernel mem.\n");
+ SCpnt->result = (DID_ERROR << 16);
+ callDone (SCpnt);
+ return NULL;
+ }
+ copy_from_user(kern_area,user_area,xfer_size);
+ pScb->kern_area = kern_area;
+ }
+
mbox->cmd = data[0];
mbox->channel = data[1];
mbox->param = data[2];
mbox->pad[0] = data[3];
mbox->logdrv = data[4];
- mbox->numsgelements = build_sglist (megaCfg, pScb,
- (u_long *) & mbox->xferaddr,
- (u_long *) & seg);
+ if(SCpnt->cmnd[0] == IOCTL_CMD_NEW) {
+ if(data[0]==DCMD_FC_CMD){ /*i.e. 0xA1, then override some mbox data */
+ *(mboxdata+0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD*/
+ *(mboxdata+2) = data[2]; /*sub command*/
+ *(mboxdata+3) = 0; /*number of elements in SG list*/
+ mbox->xferaddr /*i.e. mboxdata byte 0x8 to 0xb*/
+ = virt_to_bus(pScb->kern_area);
+ }
+ else{
+ mbox->xferaddr = virt_to_bus(pScb->kern_area);
+ mbox->numsgelements = 0;
+ }
+ }
+ else {
- for (i=0;i<(SCpnt->request_bufflen-6);i++) {
- data[i] = data[i+6];
+ mbox->numsgelements = build_sglist (megaCfg, pScb,
+ (u32 *) & mbox->xferaddr,
+ (u32 *) & seg);
+
+ for (i=0;i<(SCpnt->request_bufflen-6);i++) {
+ data[i] = data[i+6];
+ }
}
return (pScb);
@@ -808,7 +921,7 @@
{
mega_host_config *megaCfg;
u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
- u_long dword;
+ u32 dword;
mega_mailbox *mbox;
mega_scb *pScb;
long flags;
@@ -892,8 +1005,13 @@
printk("Received aborted SCB! %u\n", (int)((jiffies)-pScb->isrcount));
}
+ if (*(pScb->SCpnt->cmnd)==IOCTL_CMD_NEW)
+ { /* external user buffer */
+ up(&pScb->sem);
+ }
/* Mark command as completed */
mega_cmd_done(megaCfg, pScb, qStatus);
+
}
}
@@ -907,6 +1025,7 @@
spin_lock_irqsave(&mega_lock, flags);
mega_runpendq(megaCfg);
spin_unlock_irqrestore(&mega_lock,flags);
+
}
#if LINUX_VERSION_CODE >= 0x20100
@@ -940,6 +1059,11 @@
* u_char *mboxData - Mailbox area, 16 bytes
* mega_scb *pScb - SCB posting (or NULL if N/A)
* int intr - if 1, interrupt, 0 is blocking
+ * Return Value: (added on 7/26 for 40ld/64bit)
+ * -1: the command was not actually issued out
+ * othercases:
+ * intr==0, return ScsiStatus, i.e. mbox->status
+ * intr==1, return 0
*=====================================================
*/
static int megaIssueCmd (mega_host_config * megaCfg,
@@ -949,21 +1073,29 @@
{
mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
u_char byte;
- u_long cmdDone;
+ u32 cmdDone;
Scsi_Cmnd *SCpnt;
-
+ u32 phys_mbox;
+ u8 retval=-1;
+
mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0); /* Set cmdid */
mboxData[0xF] = 1; /* Set busy */
+ phys_mbox = virt_to_bus (megaCfg->mbox);
+
#if 0
if (intr && mbox->busy) {
return 0;
}
#endif
+#if DEBUG
+ showMbox(pScb);
+#endif
+
/* Wait until mailbox is free */
while (mega_busyWaitMbox (megaCfg)) {
- printk("Blocked mailbox!!\n");
+ printk("Blocked mailbox......!!\n");
udelay(1000);
#if DEBUG
@@ -980,12 +1112,13 @@
SCpnt->result = (DID_ABORT << 16);
callDone(SCpnt);
- return 0;
+ return -1;
}
+
pLastScb = pScb;
-
/* Copy mailbox data into host structure */
+ megaCfg->mbox64->xferSegment = 0;
memcpy (mbox, mboxData, 16);
/* Kick IO */
@@ -993,22 +1126,24 @@
/* Issue interrupt (non-blocking) command */
if (megaCfg->flag & BOARD_QUARTZ) {
- mbox->mraid_poll = 0;
+ mbox->mraid_poll = 0;
mbox->mraid_ack = 0;
- WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1);
+ WRINDOOR (megaCfg, phys_mbox | 0x1);
}
else {
ENABLE_INTR (megaCfg->host->io_port);
ISSUE_COMMAND (megaCfg->host->io_port);
}
pScb->state = SCB_ISSUED;
+
+ retval=0;
}
else { /* Issue non-ISR (blocking) command */
disable_irq(megaCfg->host->irq);
if (megaCfg->flag & BOARD_QUARTZ) {
mbox->mraid_poll = 0;
mbox->mraid_ack = 0;
- WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1);
+ WRINDOOR (megaCfg, phys_mbox | 0x1);
while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
WROUTDOOR (megaCfg, cmdDone);
@@ -1018,7 +1153,7 @@
mega_rundoneq ();
}
- WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
+ WRINDOOR (megaCfg, phys_mbox | 0x2);
while (RDINDOOR (megaCfg) & 0x2);
}
@@ -1043,20 +1178,21 @@
}
enable_irq(megaCfg->host->irq);
+ retval=mbox->status;
}
while (mega_busyWaitMbox (megaCfg)) {
- printk("Blocked mailbox on exit!\n");
+ printk("Blocked mailbox on exit......!\n");
udelay(1000);
}
- return 0;
+ return retval;
}
/*-------------------------------------------------------------------
* Copies data to SGLIST
*-------------------------------------------------------------------*/
static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
- u_long * buffer, u_long * length)
+ u32 * buffer, u32 * length)
{
struct scatterlist *sgList;
int idx;
@@ -1064,21 +1200,21 @@
/* Scatter-gather not used */
if (scb->SCpnt->use_sg == 0) {
*buffer = virt_to_bus (scb->SCpnt->request_buffer);
- *length = (u_long) scb->SCpnt->request_bufflen;
+ *length = (u32) scb->SCpnt->request_bufflen;
return 0;
}
sgList = (struct scatterlist *) scb->SCpnt->request_buffer;
if (scb->SCpnt->use_sg == 1) {
*buffer = virt_to_bus (sgList[0].address);
- *length = (u_long) sgList[0].length;
+ *length = (u32) sgList[0].length;
return 0;
}
/* Copy Scatter-Gather list info into controller structure */
for (idx = 0; idx < scb->SCpnt->use_sg; idx++) {
scb->sgList[idx].address = virt_to_bus (sgList[idx].address);
- scb->sgList[idx].length = (u_long) sgList[idx].length;
+ scb->sgList[idx].length = (u32) sgList[idx].length;
}
/* Reset pointer and length fields */
@@ -1105,12 +1241,13 @@
* 10 01 numstatus byte
* 11 01 status byte
*--------------------------------------------------------------------*/
-static int mega_register_mailbox (mega_host_config * megaCfg, u_long paddr)
+static int mega_register_mailbox (mega_host_config * megaCfg, u32 paddr)
{
/* align on 16-byte boundry */
- megaCfg->mbox = &megaCfg->mailbox;
- megaCfg->mbox = (mega_mailbox *) ((((ulong) megaCfg->mbox) + 16) & 0xfffffff0);
- paddr = (paddr + 16) & 0xfffffff0;
+ megaCfg->mbox = &megaCfg->mailbox64.mailbox;
+ megaCfg->mbox = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xfffffff0);
+ megaCfg->mbox64 = (mega_mailbox64 *) (megaCfg->mbox - 4);
+ paddr = (paddr + 4 + 16) & 0xfffffff0;
/* Register mailbox area with the firmware */
if (megaCfg->flag & BOARD_QUARTZ) {
@@ -1128,84 +1265,162 @@
return 0;
}
+
+/*---------------------------------------------------------------------------
+ * mega_Convert8ldTo40ld() -- takes all info in AdapterInquiry structure and
+ * puts it into ProductInfo and Enquiry3 structures for later use
+ *---------------------------------------------------------------------------*/
+static void mega_Convert8ldTo40ld( mega_RAIDINQ *inquiry,
+ mega_Enquiry3 *enquiry3,
+ megaRaidProductInfo *productInfo )
+{
+ int i;
+
+ productInfo->MaxConcCmds = inquiry->AdpInfo.MaxConcCmds;
+ enquiry3->rbldRate = inquiry->AdpInfo.RbldRate;
+ productInfo->SCSIChanPresent = inquiry->AdpInfo.ChanPresent;
+ for (i=0;i<4;i++) {
+ productInfo->FwVer[i] = inquiry->AdpInfo.FwVer[i];
+ productInfo->BiosVer[i] = inquiry->AdpInfo.BiosVer[i];
+ }
+ enquiry3->cacheFlushInterval = inquiry->AdpInfo.CacheFlushInterval;
+ productInfo->DramSize = inquiry->AdpInfo.DramSize;
+
+ enquiry3->numLDrv = inquiry->LogdrvInfo.NumLDrv;
+ for (i=0;i<MAX_LOGICAL_DRIVES;i++) {
+ enquiry3->lDrvSize[i] = inquiry->LogdrvInfo.LDrvSize[i];
+ enquiry3->lDrvProp[i] = inquiry->LogdrvInfo.LDrvProp[i];
+ enquiry3->lDrvState[i] = inquiry->LogdrvInfo.LDrvState[i];
+ }
+
+ for (i=0;i<(MAX_PHYSICAL_DRIVES);i++) {
+ enquiry3->pDrvState[i] = inquiry->PhysdrvInfo.PDrvState[i];
+ }
+}
+
+
/*-------------------------------------------------------------------
* Issue an adapter info query to the controller
*-------------------------------------------------------------------*/
static int mega_i_query_adapter (mega_host_config * megaCfg)
{
- mega_RAIDINQ *adapterInfo;
+ mega_Enquiry3 *enquiry3Pnt;
mega_mailbox *mbox;
u_char mboxData[16];
- u_long paddr;
+ u32 paddr;
+ u8 retval;
spin_lock_init (&mega_lock);
- /* Initialize adapter inquiry */
+ /* Initialize adapter inquiry mailbox*/
paddr = virt_to_bus (megaCfg->mega_buffer);
mbox = (mega_mailbox *) mboxData;
memset ((void *) megaCfg->mega_buffer, 0, sizeof (megaCfg->mega_buffer));
memset (mbox, 0, 16);
- /* Initialize mailbox registers */
- mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ;
- mbox->xferaddr = paddr;
+/*
+ * Try to issue Enquiry3 command
+ * if not suceeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
+ * update enquiry3 structure
+ */
+ mbox->xferaddr = virt_to_bus ( (void*) megaCfg->mega_buffer);
+ /* Initialize mailbox databuffer addr */
+ enquiry3Pnt = (mega_Enquiry3 *) megaCfg->mega_buffer;
+ /* point mega_Enguiry3 to the data buf */
+
+ mboxData[0]=FC_NEW_CONFIG ; /* i.e. mbox->cmd=0xA1 */
+ mboxData[2]=NC_SUBOP_ENQUIRY3; /* i.e. 0x0F */
+ mboxData[3]=ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */
/* Issue a blocking command to the card */
- megaIssueCmd (megaCfg, mboxData, NULL, 0);
+ if ( (retval=megaIssueCmd(megaCfg, mboxData, NULL, 0)) != 0 )
+ { /* the adapter does not support 40ld*/
- /* Initialize host/local structures with Adapter info */
- adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer;
- megaCfg->host->max_channel = adapterInfo->AdpInfo.ChanPresent;
-/* megaCfg->host->max_id = adapterInfo->AdpInfo.MaxTargPerChan; */
- megaCfg->host->max_id = 16; /* max targets/chan */
- megaCfg->numldrv = adapterInfo->LogdrvInfo.NumLDrv;
+ mega_RAIDINQ adapterInquiryData;
+ mega_RAIDINQ *adapterInquiryPnt = &adapterInquiryData;
-#if 0
- printk ("KERN_DEBUG ---- Logical drive info ----\n");
+ mbox->xferaddr = virt_to_bus ( (void*) adapterInquiryPnt);
+
+ mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; /*issue old 0x05 command to adapter*/
+ /* Issue a blocking command to the card */;
+ retval=megaIssueCmd (megaCfg, mboxData, NULL, 0);
+
+ /*update Enquiry3 and ProductInfo structures with mega_RAIDINQ structure*/
+ mega_Convert8ldTo40ld( adapterInquiryPnt,
+ enquiry3Pnt,
+ (megaRaidProductInfo * ) &megaCfg->productInfo );
+
+ }
+ else{ /* adapter supports 40ld */
+ megaCfg->flag |= BOARD_40LD;
+
+ /*get productInfo, which is static information and will be unchanged*/
+ mbox->xferaddr = virt_to_bus ( (void*) &megaCfg->productInfo );
+
+ mboxData[0]=FC_NEW_CONFIG ; /* i.e. mbox->cmd=0xA1 */
+ mboxData[2]=NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */
+
+ if( (retval=megaIssueCmd(megaCfg, mboxData, NULL, 0)) != 0 )
+ printk("ami:Product_info (0x0E) cmd failed with error: %d\n", retval);
+
+ }
+
+ megaCfg->host->max_channel = megaCfg->productInfo.SCSIChanPresent;
+ megaCfg->host->max_id = 16; /* max targets per channel */
+ /*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1;*/
+ megaCfg->host->max_lun = /* max lun */
+ (megaCfg->flag & BOARD_40LD) ? FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
+
+ megaCfg->numldrv = enquiry3Pnt->numLDrv;
+ megaCfg->max_cmds = megaCfg->productInfo.MaxConcCmds;
+
+#if 0
+ int i;
+ printk (KERN_DEBUG "---- Logical drive info from enquiry3 struct----\n");
for (i = 0; i < megaCfg->numldrv; i++) {
- printk ("%d: size: %ld prop: %x state: %x\n", i,
- adapterInfo->LogdrvInfo.LDrvSize[i],
- adapterInfo->LogdrvInfo.LDrvProp[i],
- adapterInfo->LogdrvInfo.LDrvState[i]);
+ printk ("%d: size: %d prop: %x state: %x\n", i,
+ enquiry3Pnt->lDrvSize[i],
+ enquiry3Pnt->lDrvProp[i],
+ enquiry3Pnt->lDrvState[i]);
}
+
printk (KERN_DEBUG "---- Physical drive info ----\n");
- for (i = 0; i < MAX_PHYSICAL_DRIVES; i++) {
+ for (i = 0; i < FC_MAX_PHYSICAL_DEVICES; i++) {
if (i && !(i % 8))
printk ("\n");
- printk ("%d: %x ", i, adapterInfo->PhysdrvInfo.PDrvState[i]);
+ printk ("%d: %x ", i, enquiry3Pnt->pDrvState[i]);
}
printk ("\n");
#endif
- megaCfg->max_cmds = adapterInfo->AdpInfo.MaxConcCmds;
-
#ifdef HP /* use HP firmware and bios version encoding */
sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
- adapterInfo->AdpInfo.FwVer[2],
- adapterInfo->AdpInfo.FwVer[1] >> 8,
- adapterInfo->AdpInfo.FwVer[1] & 0x0f,
- adapterInfo->AdpInfo.FwVer[2] >> 8,
- adapterInfo->AdpInfo.FwVer[2] & 0x0f);
+ megaCfg->productInfo.FwVer[2],
+ megaCfg->productInfo.FwVer[1] >> 8,
+ megaCfg->productInfo.FwVer[1] & 0x0f,
+ megaCfg->productInfo.FwVer[2] >> 8,
+ megaCfg->productInfo.FwVer[2] & 0x0f);
sprintf (megaCfg->biosVer, "%c%d%d.%d%d",
- adapterInfo->AdpInfo.BiosVer[2],
- adapterInfo->AdpInfo.BiosVer[1] >> 8,
- adapterInfo->AdpInfo.BiosVer[1] & 0x0f,
- adapterInfo->AdpInfo.BiosVer[2] >> 8,
- adapterInfo->AdpInfo.BiosVer[2] & 0x0f);
+ megaCfg->productInfo.BiosVer[2],
+ megaCfg->productInfo.BiosVer[1] >> 8,
+ megaCfg->productInfo.BiosVer[1] & 0x0f,
+ megaCfg->productInfo.BiosVer[2] >> 8,
+ megaCfg->productInfo.BiosVer[2] & 0x0f);
#else
- memcpy (megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4);
- megaCfg->fwVer[4] = 0;
+ memcpy (megaCfg->fwVer, (void *)megaCfg->productInfo.FwVer, 4);
+ megaCfg->fwVer[4] = 0;
- memcpy (megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4);
- megaCfg->biosVer[4] = 0;
+ memcpy (megaCfg->biosVer, (void *)megaCfg->productInfo.BiosVer, 4);
+ megaCfg->biosVer[4] = 0;
#endif
- printk (KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR,
- megaCfg->fwVer,
- megaCfg->biosVer,
- megaCfg->numldrv);
- return 0;
+ printk ("megaraid: [%s:%s] detected %d logical drives" CRLFSTR,
+ megaCfg->fwVer,
+ megaCfg->biosVer,
+ megaCfg->numldrv);
+
+ return 0;
}
/*-------------------------------------------------------------------------
@@ -1225,15 +1440,15 @@
}
int findCard (Scsi_Host_Template * pHostTmpl,
- u_short pciVendor, u_short pciDev,
+ u16 pciVendor, u16 pciDev,
long flag)
{
mega_host_config *megaCfg;
struct Scsi_Host *host;
u_char pciBus, pciDevFun, megaIrq;
- u_long megaBase;
- u_short jdx,pciIdx = 0;
- u_short numFound = 0;
+ u32 megaBase;
+ u16 pciIdx = 0;
+ u16 numFound = 0;
#if LINUX_VERSION_CODE < 0x20100
while (!pcibios_find_device (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) {
@@ -1249,8 +1464,8 @@
pciBus = pdev->bus->number;
pciDevFun = pdev->devfn;
#endif
- if (flag & BOARD_QUARTZ) {
- u_short magic;
+ if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
+ u16 magic;
pcibios_read_config_word (pciBus, pciDevFun,
PCI_CONF_AMISIG,
&magic);
@@ -1259,7 +1474,7 @@
continue; /* not an AMI board */
}
}
- printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n",
+ printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n",
pciVendor,
pciDev,
pciIdx, pciBus,
@@ -1272,6 +1487,7 @@
pciIdx++;
if (flag & BOARD_QUARTZ) {
+
megaBase &= PCI_BASE_ADDRESS_MEM_MASK;
megaBase = (long) ioremap (megaBase, 128);
}
@@ -1285,7 +1501,7 @@
megaCfg = (mega_host_config *) host->hostdata;
memset (megaCfg, 0, sizeof (mega_host_config));
- printk (" scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR,
+ printk ("scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR,
host->host_no, (u_int) megaBase, megaIrq);
/* Copy resource info into structure */
@@ -1298,8 +1514,7 @@
megaCfg->host->io_port = megaBase;
megaCfg->host->n_io_port = 16;
megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;
- megaCtlrs[numCtlrs++] = megaCfg;
-
+ megaCtlrs[numCtlrs++] = megaCfg;
if (flag != BOARD_QUARTZ) {
/* Request our IO Range */
if (check_region (megaBase, 16)) {
@@ -1319,14 +1534,9 @@
continue;
}
- mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox));
+ mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox64));
mega_i_query_adapter (megaCfg);
- for(jdx=0; jdx<MAX_LOGICAL_DRIVES; jdx++) {
- megaCfg->nReads[jdx] = 0;
- megaCfg->nWrites[jdx] = 0;
- }
-
/* Initialize SCBs */
if (initSCB (megaCfg)) {
scsi_unregister (host);
@@ -1364,6 +1574,8 @@
skip_id = (skip_id > 15) ? -1 : skip_id;
}
+ printk ("megaraid: " MEGARAID_VERSION CRLFSTR);
+
count += findCard (pHostTmpl, 0x101E, 0x9010, 0);
count += findCard (pHostTmpl, 0x101E, 0x9060, 0);
count += findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
@@ -1424,16 +1636,15 @@
{
static char buffer[512];
mega_host_config *megaCfg;
- mega_RAIDINQ *adapterInfo;
megaCfg = (mega_host_config *) pSHost->hostdata;
- adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer;
- sprintf (buffer, "AMI MegaRAID %s %d commands %d targs %d chans",
+ sprintf (buffer, "AMI MegaRAID %s %d commands %d targs %d chans %d luns",
megaCfg->fwVer,
- adapterInfo->AdpInfo.MaxConcCmds,
+ megaCfg->productInfo.MaxConcCmds,
megaCfg->host->max_id,
- megaCfg->host->max_channel);
+ megaCfg->host->max_channel,
+ megaCfg->host->max_lun);
return buffer;
}
@@ -1463,9 +1674,13 @@
megaCfg = (mega_host_config *) SCpnt->host->hostdata;
if (!(megaCfg->flag & (1L << SCpnt->channel))) {
- printk (KERN_INFO "scsi%d: scanning channel %c for devices.\n",
+ if (SCpnt->channel < SCpnt->host->max_channel)
+ printk (/*KERN_INFO*/ "scsi%d: scanning channel %c for devices.\n",
megaCfg->host->host_no,
- SCpnt->channel + 'A');
+ SCpnt->channel + '1');
+ else
+ printk(/*KERN_INFO*/ "scsi%d: scanning virtual channel for logical drives.\n", megaCfg->host->host_no);
+
megaCfg->flag |= (1L << SCpnt->channel);
}
@@ -1489,6 +1704,7 @@
/* Allocate and build a SCB request */
if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) {
+ /*build SCpnt for IOCTL_CMD_NEW cmd in mega_ioctl()*/
/* Add SCB to the head of the pending queue */
ENQUEUE_NL (pScb, mega_scb, megaCfg->qPending, next);
@@ -1499,6 +1715,25 @@
else {
printk("IRQ pend...\n");
}
+
+ if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW )
+ { /* user data from external user buffer */
+ char *user_area;
+ u32 xfer_size;
+
+ init_MUTEX_LOCKED(&pScb->sem);
+ down(&pScb->sem);
+
+ user_area = *((char **)&pScb->SCpnt->cmnd[4]);
+ xfer_size = *((u32 *)&pScb->SCpnt->cmnd[8]);
+
+ copy_to_user(user_area,pScb->kern_area,xfer_size);
+
+ kfree(pScb->kern_area);
+
+ freeSCB(megaCfg, pScb);
+ }
+
}
spin_unlock_irqrestore(&mega_lock,flags);
@@ -1699,3 +1934,4 @@
#include "scsi_module.c"
#endif
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)