📄 megaraid.c
字号:
switch (mbox->m_out.cmd) { case MEGA_MBOXCMD_LREAD64: case MEGA_MBOXCMD_LWRITE64: case MEGA_MBOXCMD_PASSTHRU64: case MEGA_MBOXCMD_EXTPTHRU: mbox64->xfer_segment_lo = mbox->m_out.xferaddr; mbox64->xfer_segment_hi = 0; mbox->m_out.xferaddr = 0xFFFFFFFF; break; default: mbox64->xfer_segment_lo = 0; mbox64->xfer_segment_hi = 0; } /* * post the command */ scb->state |= SCB_ISSUED; if( likely(adapter->flag & BOARD_MEMMAP) ) { mbox->m_in.poll = 0; mbox->m_in.ack = 0; WRINDOOR(adapter, adapter->mbox_dma | 0x1); } else { irq_enable(adapter); issue_command(adapter); } return 0;}/* * Wait until the controller's mailbox is available */static inline intmega_busywait_mbox (adapter_t *adapter){ if (adapter->mbox->m_in.busy) return __mega_busywait_mbox(adapter); return 0;}/** * issue_scb_block() * @adapter - pointer to our soft state * @raw_mbox - the mailbox * * Issue a scb in synchronous and non-interrupt mode */static intissue_scb_block(adapter_t *adapter, u_char *raw_mbox){ volatile mbox64_t *mbox64 = adapter->mbox64; volatile mbox_t *mbox = adapter->mbox; u8 byte; /* Wait until mailbox is free */ if(mega_busywait_mbox (adapter)) goto bug_blocked_mailbox; /* Copy mailbox data into host structure */ memcpy((char *) mbox, raw_mbox, sizeof(struct mbox_out)); mbox->m_out.cmdid = 0xFE; mbox->m_in.busy = 1; switch (raw_mbox[0]) { case MEGA_MBOXCMD_LREAD64: case MEGA_MBOXCMD_LWRITE64: case MEGA_MBOXCMD_PASSTHRU64: case MEGA_MBOXCMD_EXTPTHRU: mbox64->xfer_segment_lo = mbox->m_out.xferaddr; mbox64->xfer_segment_hi = 0; mbox->m_out.xferaddr = 0xFFFFFFFF; break; default: mbox64->xfer_segment_lo = 0; mbox64->xfer_segment_hi = 0; } if( likely(adapter->flag & BOARD_MEMMAP) ) { mbox->m_in.poll = 0; mbox->m_in.ack = 0; mbox->m_in.numstatus = 0xFF; mbox->m_in.status = 0xFF; WRINDOOR(adapter, adapter->mbox_dma | 0x1); while((volatile u8)mbox->m_in.numstatus == 0xFF) cpu_relax(); mbox->m_in.numstatus = 0xFF; while( (volatile u8)mbox->m_in.poll != 0x77 ) cpu_relax(); mbox->m_in.poll = 0; mbox->m_in.ack = 0x77; WRINDOOR(adapter, adapter->mbox_dma | 0x2); while(RDINDOOR(adapter) & 0x2) cpu_relax(); } else { irq_disable(adapter); issue_command(adapter); while (!((byte = irq_state(adapter)) & INTR_VALID)) cpu_relax(); set_irq_state(adapter, byte); irq_enable(adapter); irq_ack(adapter); } return mbox->m_in.status;bug_blocked_mailbox: printk(KERN_WARNING "megaraid: Blocked mailbox......!!\n"); udelay (1000); return -1;}/** * megaraid_isr_iomapped() * @irq - irq * @devp - pointer to our soft state * * Interrupt service routine for io-mapped controllers. * Find out if our device is interrupting. If yes, acknowledge the interrupt * and service the completed commands. */static irqreturn_tmegaraid_isr_iomapped(int irq, void *devp){ adapter_t *adapter = devp; unsigned long flags; u8 status; u8 nstatus; u8 completed[MAX_FIRMWARE_STATUS]; u8 byte; int handled = 0; /* * loop till F/W has more commands for us to complete. */ spin_lock_irqsave(&adapter->lock, flags); do { /* Check if a valid interrupt is pending */ byte = irq_state(adapter); if( (byte & VALID_INTR_BYTE) == 0 ) { /* * No more pending commands */ goto out_unlock; } set_irq_state(adapter, byte); while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus) == 0xFF) cpu_relax(); adapter->mbox->m_in.numstatus = 0xFF; status = adapter->mbox->m_in.status; /* * decrement the pending queue counter */ atomic_sub(nstatus, &adapter->pend_cmds); memcpy(completed, (void *)adapter->mbox->m_in.completed, nstatus); /* Acknowledge interrupt */ irq_ack(adapter); mega_cmd_done(adapter, completed, nstatus, status); mega_rundoneq(adapter); handled = 1; /* Loop through any pending requests */ if(atomic_read(&adapter->quiescent) == 0) { mega_runpendq(adapter); } } while(1); out_unlock: spin_unlock_irqrestore(&adapter->lock, flags); return IRQ_RETVAL(handled);}/** * megaraid_isr_memmapped() * @irq - irq * @devp - pointer to our soft state * * Interrupt service routine for memory-mapped controllers. * Find out if our device is interrupting. If yes, acknowledge the interrupt * and service the completed commands. */static irqreturn_tmegaraid_isr_memmapped(int irq, void *devp){ adapter_t *adapter = devp; unsigned long flags; u8 status; u32 dword = 0; u8 nstatus; u8 completed[MAX_FIRMWARE_STATUS]; int handled = 0; /* * loop till F/W has more commands for us to complete. */ spin_lock_irqsave(&adapter->lock, flags); do { /* Check if a valid interrupt is pending */ dword = RDOUTDOOR(adapter); if(dword != 0x10001234) { /* * No more pending commands */ goto out_unlock; } WROUTDOOR(adapter, 0x10001234); while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus) == 0xFF) { cpu_relax(); } adapter->mbox->m_in.numstatus = 0xFF; status = adapter->mbox->m_in.status; /* * decrement the pending queue counter */ atomic_sub(nstatus, &adapter->pend_cmds); memcpy(completed, (void *)adapter->mbox->m_in.completed, nstatus); /* Acknowledge interrupt */ WRINDOOR(adapter, 0x2); handled = 1; while( RDINDOOR(adapter) & 0x02 ) cpu_relax(); mega_cmd_done(adapter, completed, nstatus, status); mega_rundoneq(adapter); /* Loop through any pending requests */ if(atomic_read(&adapter->quiescent) == 0) { mega_runpendq(adapter); } } while(1); out_unlock: spin_unlock_irqrestore(&adapter->lock, flags); return IRQ_RETVAL(handled);}/** * mega_cmd_done() * @adapter - pointer to our soft state * @completed - array of ids of completed commands * @nstatus - number of completed commands * @status - status of the last command completed * * Complete the comamnds and call the scsi mid-layer callback hooks. */static voidmega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status){ mega_ext_passthru *epthru = NULL; struct scatterlist *sgl; Scsi_Cmnd *cmd = NULL; mega_passthru *pthru = NULL; mbox_t *mbox = NULL; u8 c; scb_t *scb; int islogical; int cmdid; int i; /* * for all the commands completed, call the mid-layer callback routine * and free the scb. */ for( i = 0; i < nstatus; i++ ) { cmdid = completed[i]; if( cmdid == CMDID_INT_CMDS ) { /* internal command */ scb = &adapter->int_scb; cmd = scb->cmd; mbox = (mbox_t *)scb->raw_mbox; /* * Internal command interface do not fire the extended * passthru or 64-bit passthru */ pthru = scb->pthru; } else { scb = &adapter->scb_list[cmdid]; /* * Make sure f/w has completed a valid command */ if( !(scb->state & SCB_ISSUED) || scb->cmd == NULL ) { printk(KERN_CRIT "megaraid: invalid command "); printk("Id %d, scb->state:%x, scsi cmd:%p\n", cmdid, scb->state, scb->cmd); continue; } /* * Was a abort issued for this command */ if( scb->state & SCB_ABORT ) { printk(KERN_WARNING "megaraid: aborted cmd %lx[%x] complete.\n", scb->cmd->serial_number, scb->idx); scb->cmd->result = (DID_ABORT << 16); list_add_tail(SCSI_LIST(scb->cmd), &adapter->completed_list); mega_free_scb(adapter, scb); continue; } /* * Was a reset issued for this command */ if( scb->state & SCB_RESET ) { printk(KERN_WARNING "megaraid: reset cmd %lx[%x] complete.\n", scb->cmd->serial_number, scb->idx); scb->cmd->result = (DID_RESET << 16); list_add_tail(SCSI_LIST(scb->cmd), &adapter->completed_list); mega_free_scb (adapter, scb); continue; } cmd = scb->cmd; pthru = scb->pthru; epthru = scb->epthru; mbox = (mbox_t *)scb->raw_mbox;#if MEGA_HAVE_STATS { int logdrv = mbox->m_out.logdrv; islogical = adapter->logdrv_chan[cmd->channel]; /* * Maintain an error counter for the logical drive. * Some application like SNMP agent need such * statistics */ if( status && islogical && (cmd->cmnd[0] == READ_6 || cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == READ_12)) { /* * Logical drive number increases by 0x80 when * a logical drive is deleted */ adapter->rd_errors[logdrv%0x80]++; } if( status && islogical && (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 || cmd->cmnd[0] == WRITE_12)) { /* * Logical drive number increases by 0x80 when * a logical drive is deleted */ adapter->wr_errors[logdrv%0x80]++; } }#endif } /* * Do not return the presence of hard disk on the channel so, * inquiry sent, and returned data==hard disk or removable * hard disk and not logical, request should return failure! - * PJ */ islogical = adapter->logdrv_chan[cmd->device->channel]; if( cmd->cmnd[0] == INQUIRY && !islogical ) { sgl = scsi_sglist(cmd); if( sg_page(sgl) ) { c = *(unsigned char *) sg_virt(&sgl[0]); } else { printk(KERN_WARNING "megaraid: invalid sg.\n"); c = 0; } if(IS_RAID_CH(adapter, cmd->device->channel) && ((c & 0x1F ) == TYPE_DISK)) { status = 0xF0; } } /* clear result; otherwise, success returns corrupt value */ cmd->result = 0; /* Convert MegaRAID status to Linux error code */ switch (status) { case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD */ cmd->result |= (DID_OK << 16); break; case 0x02: /* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */ /* set sense_buffer and result fields */ if( mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU || mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU64 ) { memcpy(cmd->sense_buffer, pthru->reqsensearea, 14); cmd->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1); } else { if (mbox->m_out.cmd == MEGA_MBOXCMD_EXTPTHRU) { memcpy(cmd->sense_buffer, epthru->reqsensearea, 14); cmd->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1); } else { cmd->sense_buffer[0] = 0x70; cmd->sense_buffer[2] = ABORTED_COMMAND; cmd->result |= (CHECK_CONDITION << 1); } } break; case 0x08: /* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */ cmd->result |= (DID_BUS_BUSY << 16) | status; break; default:#if MEGA_HAVE_CLUSTERING /* * If TEST_UNIT_READY fails, we know * MEGA_RESERVATION_STATUS failed */ if( cmd->cmnd[0] == TEST_UNIT_READY ) { cmd->result |= (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1); } else /* * Error code returned is 1 if Reserve or Release * failed or the input parameter is invalid */ if( status == 1 && (cmd->cmnd[0] == RESERVE || cmd->cmnd[0] == RELEASE) ) { cmd->result |= (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1); } else#endif cmd->result |= (DID_BAD_TARGET << 16)|status; } /* * Only free SCBs for the commands coming down from the * mid-layer, not for which were issued internally * * For internal command, restore the status returned by the * firmware so that user can interpret it. */ if( cmdid == CMDID_INT_CMDS ) { /* internal command */ cmd->result = status; /* * Remove the internal command from the pending list */ list_del_init(&scb->list); scb->state = SCB_FREE; } else { mega_free_scb(adapter, scb); } /* Add Scsi_Command to end of completed queue */ list_add_tail(SCSI_LIST(cmd), &adapter->completed_list); }}/* * mega_runpendq() * * Run through the list of completed requests and finish it */static voidmega_rundoneq (adapter_t *adapter){ Scsi_Cmnd *cmd; struct list_head *pos; list_for_each(pos, &adapter->completed_list) { struct scsi_pointer* spos = (struct scsi_pointer *)pos; cmd = list_entry(spos, Scsi_Cmnd, SCp); cmd->scsi_done(cmd); } INIT_LIST_HEAD(&adapter->completed_list);}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -