📄 megaraid.c
字号:
/* Issue any pending commands to the card */ for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) { if (pScb->state == SCB_ACTIVE) { if(megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1)) return; } }}/* Add command to the list of completed requests */static voidmega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int status){ int islogical; Scsi_Cmnd *SCpnt; mega_passthru *pthru; mega_mailbox *mbox; if (pScb == NULL) { TRACE(("NULL pScb in mega_cmd_done!")); printk("NULL pScb in mega_cmd_done!"); } SCpnt = pScb->SCpnt; pthru = &pScb->pthru; mbox = (mega_mailbox *) &pScb->mboxData; if (SCpnt == NULL) { TRACE(("NULL SCpnt in mega_cmd_done!")); TRACE(("pScb->idx = ",pScb->idx)); TRACE(("pScb->state = ",pScb->state)); TRACE(("pScb->state = ",pScb->state)); printk("megaraid:Problem...!\n"); while(1); } islogical = (SCpnt->channel == megaCfg->host->max_channel); if (SCpnt->cmnd[0] == INQUIRY && ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && !islogical) { status = 0xF0; }/* 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 , i.e. SCSI_STATUS_GOOD*/ SCpnt->result |= (DID_OK << 16); break; 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; 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*/ mega_freeSCB(megaCfg, pScb); /* Add Scsi_Command to end of completed queue */ if( megaCfg->qCompletedH == NULL ) { megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt; } else { megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt; megaCfg->qCompletedT = SCpnt; } megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; megaCfg->qCcnt++;}/*------------------------------------------------------------------- * * Build a SCB from a Scsi_Cmnd * * Returns a SCB pointer, or NULL * If NULL is returned, the scsi_done function MUST have been called * *-------------------------------------------------------------------*/static mega_scb * mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt){ mega_scb *pScb; mega_mailbox *mbox; mega_passthru *pthru; long seg; char islogical; char lun = SCpnt->lun; if ((SCpnt->cmnd[0] == 0x80) || (SCpnt->cmnd[0] == IOCTL_CMD_NEW) ) /* ioctl */ return mega_ioctl (megaCfg, SCpnt); islogical = (SCpnt->channel == megaCfg->host->max_channel); if (!islogical && lun != 0) { SCpnt->result = (DID_BAD_TARGET << 16); callDone (SCpnt); return NULL; } if (!islogical && SCpnt->target == skip_id) { SCpnt->result = (DID_BAD_TARGET << 16); callDone (SCpnt); return NULL; } if ( islogical ) { lun = (SCpnt->target * 8) + lun; if ( lun > FC_MAX_LOGICAL_DRIVES ){ SCpnt->result = (DID_BAD_TARGET << 16); callDone (SCpnt); return NULL; } } /*----------------------------------------------------- * * Logical drive commands * *-----------------------------------------------------*/ if (islogical) { switch (SCpnt->cmnd[0]) { case TEST_UNIT_READY: memset (SCpnt->request_buffer, 0, SCpnt->request_bufflen); SCpnt->result = (DID_OK << 16); callDone (SCpnt); return NULL; case MODE_SENSE: memset (SCpnt->request_buffer, 0, SCpnt->cmnd[4]); SCpnt->result = (DID_OK << 16); callDone (SCpnt); return NULL; case READ_CAPACITY: case INQUIRY: /* Allocate a SCB and initialize passthru */ if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); callDone (SCpnt); return NULL; } pthru = &pScb->pthru; mbox = (mega_mailbox *) & pScb->mboxData; memset (mbox, 0, sizeof (pScb->mboxData)); memset (pthru, 0, sizeof (mega_passthru)); pthru->timeout = 0; pthru->ars = 1; pthru->reqsenselen = 14; pthru->islogical = 1; pthru->logdrv = lun; pthru->cdblen = SCpnt->cmd_len; pthru->dataxferaddr = virt_to_bus (SCpnt->request_buffer); pthru->dataxferlen = SCpnt->request_bufflen; memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); /* Initialize mailbox area */ mbox->cmd = MEGA_MBOXCMD_PASSTHRU; mbox->xferaddr = virt_to_bus (pthru); return pScb; case READ_6: case WRITE_6: case READ_10: case WRITE_10: /* Allocate a SCB and initialize mailbox */ if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); callDone (SCpnt); return NULL; } mbox = (mega_mailbox *) & pScb->mboxData; memset (mbox, 0, sizeof (pScb->mboxData)); 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 = (u32) SCpnt->cmnd[4]; mbox->lba = ((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 = (u32) SCpnt->cmnd[8] | ((u32) SCpnt->cmnd[7] << 8); mbox->lba = ((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 = mega_build_sglist (megaCfg, pScb, (u32 *) & mbox->xferaddr, (u32 *) & seg); return pScb; default: SCpnt->result = (DID_BAD_TARGET << 16); callDone (SCpnt); return NULL; } } /*----------------------------------------------------- * * Passthru drive commands * *-----------------------------------------------------*/ else { /* Allocate a SCB and initialize passthru */ if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); callDone (SCpnt); return NULL; } pthru = &pScb->pthru; mbox = (mega_mailbox *) pScb->mboxData; memset (mbox, 0, sizeof (pScb->mboxData)); memset (pthru, 0, sizeof (mega_passthru)); 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 = (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 = mega_build_sglist (megaCfg, pScb, (u32 *) & pthru->dataxferaddr, (u32 *) & pthru->dataxferlen); /* Initialize mailbox */ mbox->cmd = MEGA_MBOXCMD_PASSTHRU; mbox->xferaddr = virt_to_bus (pthru); return pScb; } return NULL;}/*-------------------------------------------------------------------- * build RAID commands for controller, passed down through ioctl() *--------------------------------------------------------------------*/static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt){ mega_scb *pScb; mega_ioctl_mbox *mbox; mega_mailbox *mailbox; mega_passthru *pthru; u8 *mboxdata; long seg; unsigned char *data = (unsigned char *)SCpnt->request_buffer; int i; if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); callDone (SCpnt); return NULL; } 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; pthru->timeout = data[cdblen+3] & 0x07; pthru->reqsenselen = 14; pthru->ars = (data[cdblen+3] & 0x08) ? 1:0; pthru->logdrv = data[cdblen+4]; pthru->channel = data[cdblen+5]; pthru->target = data[cdblen+6]; pthru->cdblen = cdblen; memcpy (pthru->cdb, &data[3], cdblen); mailbox->cmd = MEGA_MBOXCMD_PASSTHRU; mailbox->xferaddr = virt_to_bus (pthru); pthru->numsgelements = mega_build_sglist (megaCfg, pScb, (u32 *) & pthru->dataxferaddr, (u32 *) & pthru->dataxferlen); for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) { data[i] = data[i+cdblen+7]; } return pScb; } /* else normal (nonpassthru) command */#if LINUX_VERSION_CODE > 0x020024/* * usage of the function copy from user is used in case of data more than * 4KB. This is used only with adapters which supports more than 8 logical * drives. This feature is disabled on kernels earlier or same as 2.0.36 * as the uaccess.h file is not available with those kernels. */ 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; }#endif mbox->cmd = data[0]; mbox->channel = data[1]; mbox->param = data[2]; mbox->pad[0] = data[3]; mbox->logdrv = data[4]; 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 { mbox->numsgelements = mega_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);}#if DEBUGstatic void showMbox(mega_scb *pScb){ mega_mailbox *mbox; if (pScb == NULL) return; mbox = (mega_mailbox *)pScb->mboxData; printk("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n", pScb->SCpnt->pid, mbox->cmd, mbox->cmdid, mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv, mbox->numsgelements);}#endif#if DEBUGstatic unsigned int cum_time = 0;static unsigned int cum_time_cnt = 0;#endif/*-------------------------------------------------------------------- * Interrupt service routine *--------------------------------------------------------------------*/static void megaraid_isr (int irq, void *devp, struct pt_regs *regs){#if LINUX_VERSION_CODE >= 0x20100 IO_LOCK_T#endif mega_host_config *megaCfg; u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE]; u32 dword=0; mega_mailbox *mbox; mega_scb *pScb; u_char qCnt, qStatus; u_char completed[MAX_FIRMWARE_STATUS]; Scsi_Cmnd *SCpnt; megaCfg = (mega_host_config *) devp; mbox = (mega_mailbox *)tmpBox; if (megaCfg->host->irq == irq) { if (megaCfg->flag & IN_ISR) { printk(KERN_ERR "ISR called reentrantly!!\n"); } megaCfg->flag |= IN_ISR; if (mega_busyWaitMbox(megaCfg)) { printk(KERN_WARNING "Error: mailbox busy in isr!\n"); } /* Check if a valid interrupt is pending */ if (megaCfg->flag & BOARD_QUARTZ) { dword = RDOUTDOOR (megaCfg); if (dword != 0x10001234) { /* Spurious interrupt */ megaCfg->flag &= ~IN_ISR; return; } } else { byte = READ_PORT (megaCfg->host->io_port, INTR_PORT); if ((byte & VALID_INTR_BYTE) == 0) { /* Spurious interrupt */ megaCfg->flag &= ~IN_ISR; return; } WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); } for(idx=0;idx<MAX_FIRMWARE_STATUS;idx++ ) completed[idx] = 0; IO_LOCK; qCnt = 0xff; while ((qCnt = megaCfg->mbox->numstatus) == 0xFF) ; qStatus = 0xff; while ((qStatus = megaCfg->mbox->status) == 0xFF) ; /* Get list of completed requests */ for (idx = 0; idx<qCnt; idx++) { while ((sIdx = megaCfg->mbox->completed[idx]) == 0xFF) { printk("p"); } completed[idx] = sIdx; sIdx = 0xFF; } if (megaCfg->flag & BOARD_QUARTZ) { WROUTDOOR (megaCfg, dword); /* Acknowledge interrupt */ WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -