📄 megaraid.c
字号:
FROMTO_DEVICE); mbox->numsgelements = 0; break; case DCMD_CHANGE_LDNO: case DCMD_CHANGE_LOOPID: *(mboxdata + 3) = data[2]; *(mboxdata + 4) = data[3]; set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE); mbox->numsgelements = 0; break; default: set_mbox_xfer_addr (megaCfg, pScb, mbox, FROMTO_DEVICE); mbox->numsgelements = 0; break; } /*switch */ break; default: set_mbox_xfer_addr (megaCfg, pScb, mbox, FROMTO_DEVICE); mbox->numsgelements = 0; break; } } else { mbox->numsgelements = mega_build_sglist (megaCfg, pScb, (u32 *) & mbox-> xferaddr, (u32 *) & seg); /* Handling some of the fw special commands */ switch (data[0]) { case 6: /* START_DEV */ mbox->xferaddr = *((u32 *) & data[i + 6]); break; default: break; } for (i = 0; i < (SCpnt->request_bufflen - 6); i++) { data[i] = data[i + 6]; } } return (pScb);}static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb, mega_ioctl_mbox * mbox){ ulong i, buffer_area, len, end, end_page, x, idx = 0; buffer_area = (ulong) barea; i = buffer_area; end = buffer_area + xfersize; end_page = (end) & ~(PAGE_SIZE - 1); do { len = PAGE_SIZE - (i % PAGE_SIZE); x = pScb->sgList[idx].address = virt_to_bus ((volatile void *) i); pScb->sgList[idx].length = len; i += len; idx++; } while (i < end_page); if ((end - i) < 0) { printk ("megaraid:Error in user address\n"); } if (end - i) { pScb->sgList[idx].address = virt_to_bus ((volatile void *) i); pScb->sgList[idx].length = end - i; idx++; } mbox->xferaddr = virt_to_bus (pScb->sgList); mbox->numsgelements = idx;}#endif#if DEBUGstatic unsigned int cum_time = 0;static unsigned int cum_time_cnt = 0;static 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/*-------------------------------------------------------------------- * Interrupt service routine *--------------------------------------------------------------------*/static void megaraid_isr (int irq, void *devp, struct pt_regs *regs){ IO_LOCK_T; 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) { TRACE (("ISR called reentrantly!!\n")); printk ("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; megaCfg->nInterrupts++; 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 */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* In this case mbox contains physical address */#if 0 WRINDOOR (megaCfg, megaCfg->adjdmahandle64 | 0x2);#else WRINDOOR (megaCfg, 0x2);#endif#else#if 0 WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);#else WRINDOOR (megaCfg, 0x2);#endif#endif#if 0 while (RDINDOOR (megaCfg) & 0x02) ;#endif } else { CLEAR_INTR (megaCfg->host->io_port); }#if DEBUG if (qCnt >= MAX_FIRMWARE_STATUS) { printk ("megaraid_isr: cmplt=%d ", qCnt); }#endif for (idx = 0; idx < qCnt; idx++) { sIdx = completed[idx]; if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) { pScb = &megaCfg->scbList[sIdx - 1]; /* ASSERT(pScb->state == SCB_ISSUED); */#if DEBUG if (((jiffies) - pScb->isrcount) > maxCmdTime) { maxCmdTime = (jiffies) - pScb->isrcount; printk ("megaraid_isr : cmd time = %u\n", maxCmdTime); }#endif /* * Assuming that the scsi command, for which * an abort request was received earlier, has * completed. */ if (pScb->state == SCB_ABORTED) { SCpnt = pScb->SCpnt; } if (pScb->state == SCB_RESET) { SCpnt = pScb->SCpnt; mega_freeSCB (megaCfg, pScb); SCpnt->result = (DID_RESET << 16); 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++; continue; } /* We don't want the ISR routine to touch M_RD_IOCTL_CMD_NEW commands, so * don't mark them as complete, instead we pop their semaphore so * that the queue routine can finish them off */ if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) { /* save the status byte for the queue routine to use */ pScb->SCpnt->result = qStatus; up (&pScb->ioctl_sem); } else { /* Mark command as completed */ mega_cmd_done (megaCfg, pScb, qStatus); } } else { printk ("megaraid: wrong cmd id completed from firmware:id=%x\n", sIdx); } } mega_rundoneq (megaCfg); megaCfg->flag &= ~IN_ISR; /* Loop through any pending requests */ mega_runpendq (megaCfg); IO_UNLOCK; }}/*==================================================*//* Wait until the controller's mailbox is available *//*==================================================*/static int mega_busyWaitMbox (mega_host_config * megaCfg){ mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; long counter; for (counter = 0; counter < 10000; counter++) { if (!mbox->busy) { return 0; } udelay (100); barrier (); } return -1; /* give up after 1 second */}/*===================================================== * Post a command to the card * * Arguments: * mega_host_config *megaCfg - Controller structure * 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 * other cases: * intr==0, return ScsiStatus, i.e. mbox->status * intr==1, return 0 *===================================================== */static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData, mega_scb * pScb, int intr){ volatile mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) volatile mega_mailbox64 *mbox64 = (mega_mailbox64 *) megaCfg->mbox64;#endif u_char byte;#ifdef __LP64__ u64 phys_mbox;#else u32 phys_mbox;#endif u8 retval = -1; mboxData[0x1] = (pScb ? pScb->idx + 1 : 0xFE); /* Set cmdid */ mboxData[0xF] = 1; /* Set busy */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* In this case mbox contains physical address */ phys_mbox = megaCfg->adjdmahandle64;#else phys_mbox = virt_to_bus (megaCfg->mbox);#endif#if DEBUG ShowMbox (pScb);#endif /* Wait until mailbox is free */ if (mega_busyWaitMbox (megaCfg)) { printk ("Blocked mailbox......!!\n"); udelay (1000);#if DEBUG showMbox (pLastScb);#endif /* Abort command */ if (pScb == NULL) { TRACE (("NULL pScb in megaIssue\n")); printk ("NULL pScb in megaIssue\n"); } mega_cmd_done (megaCfg, pScb, 0x08); return -1; } pLastScb = pScb; /* Copy mailbox data into host structure */ megaCfg->mbox64->xferSegment_lo = 0; megaCfg->mbox64->xferSegment_hi = 0; memcpy ((char *) mbox, mboxData, 16);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) switch (mboxData[0]) { case MEGA_MBOXCMD_LREAD64: case MEGA_MBOXCMD_LWRITE64: mbox64->xferSegment_lo = mbox->xferaddr; mbox64->xferSegment_hi = 0; mbox->xferaddr = 0xFFFFFFFF; break; }#endif /* Kick IO */ if (intr) { /* Issue interrupt (non-blocking) command */ if (megaCfg->flag & BOARD_QUARTZ) { mbox->mraid_poll = 0; mbox->mraid_ack = 0; 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; mbox->numstatus = 0xFF; mbox->status = 0xFF; WRINDOOR (megaCfg, phys_mbox | 0x1); while (mbox->numstatus == 0xFF) ; while (mbox->status == 0xFF) ; while (mbox->mraid_poll != 0x77) ; mbox->mraid_poll = 0; mbox->mraid_ack = 0x77; /* while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234); WROUTDOOR (megaCfg, cmdDone); */ if (pScb) { mega_cmd_done (megaCfg, pScb, mbox->status); } WRINDOOR (megaCfg, phys_mbox | 0x2); while (RDINDOOR (megaCfg) & 0x2) ; } else { DISABLE_INTR (megaCfg->host->io_port); ISSUE_COMMAND (megaCfg->host->io_port); while (! ((byte = READ_PORT (megaCfg->host->io_port, INTR_PORT)) & INTR_VALID)) ; WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); ENABLE_INTR (megaCfg->host->io_port); CLEAR_INTR (megaCfg->host->io_port); if (pScb) { mega_cmd_done (megaCfg, pScb, mbox->status); } else { TRACE (("Error: NULL pScb!\n")); } } enable_irq (megaCfg->host->irq); retval = mbox->status; }#if DEBUG while (mega_busyWaitMbox (megaCfg)) { printk(KERN_ERR "Blocked mailbox on exit......!\n"); udelay (1000); }#endif return retval;}/*------------------------------------------------------------------- * Copies data to SGLIST *-------------------------------------------------------------------*//* Note: For 64 bit cards, we need a minimum of one SG element for read/write*/static intmega_build_sglist (mega_host_config * megaCfg, mega_scb * scb, u32 * buffer, u32 * length){ struct scatterlist *sgList; int idx;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) int sgcnt;#endif mega_mailbox *mbox = NULL; mbox = (mega_mailbox *) scb->mboxData; /* Scatter-gather not used */ if (scb->SCpnt->use_sg == 0) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) scb->dma_h_bulkdata = pci_map_single (megaCfg->dev, scb->SCpnt->request_buffer, scb->SCpnt->request_bufflen, scb->dma_direction); /* We need to handle special commands like READ64, WRITE64 as they need a minimum of 1 SG irrespective of actually SG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -