nsp32.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,409 行 · 第 1/5 页
C
2,409 行
if (data->CurrentSC != NULL) { nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request"); data->CurrentSC = NULL; SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return SCSI_MLQUEUE_HOST_BUSY; } /* check target ID is not same as this initiator ID */ if (SCpnt->device->id == SCpnt->device->host->this_id) { nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "terget==host???"); SCpnt->result = DID_BAD_TARGET << 16; done(SCpnt); return SCSI_MLQUEUE_DEVICE_BUSY; } /* check target LUN is allowable value */ if (SCpnt->device->lun >= MAX_LUN) { nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "no more lun"); SCpnt->result = DID_BAD_TARGET << 16; done(SCpnt); return SCSI_MLQUEUE_DEVICE_BUSY; } show_command(SCpnt); SCpnt->scsi_done = done; data->CurrentSC = SCpnt; SCpnt->SCp.Status = CHECK_CONDITION; SCpnt->SCp.Message = 0; SCpnt->resid = SCpnt->request_bufflen; SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; SCpnt->SCp.this_residual = SCpnt->request_bufflen; SCpnt->SCp.buffer = NULL; SCpnt->SCp.buffers_residual = 0; /* initialize data */ data->msgout_len = 0; data->msgin_len = 0; cur_lunt = &(data->lunt[SCpnt->device->id][SCpnt->device->lun]); cur_lunt->SCpnt = SCpnt; cur_lunt->save_datp = 0; cur_lunt->msgin03 = FALSE; data->cur_lunt = cur_lunt; data->cur_id = SCpnt->device->id; data->cur_lun = SCpnt->device->lun; ret = nsp32_setup_sg_table(SCpnt); if (ret == FALSE) { nsp32_msg(KERN_ERR, "SGT fail"); SCpnt->result = DID_ERROR << 16; nsp32_scsi_done(SCpnt); return SCSI_MLQUEUE_HOST_BUSY; } /* Build IDENTIFY */ nsp32_build_identify(SCpnt); /* * If target is the first time to transfer after the reset * (target don't have SDTR_DONE and SDTR_INITIATOR), sync * message SDTR is needed to do synchronous transfer. */ target = &data->target[SCpnt->device->id]; data->cur_target = target; if (!(target->sync_flag & (SDTR_DONE | SDTR_INITIATOR | SDTR_TARGET))) { unsigned char period, offset; if (trans_mode != ASYNC_MODE) { nsp32_set_max_sync(data, target, &period, &offset); nsp32_build_sdtr(SCpnt, period, offset); target->sync_flag |= SDTR_INITIATOR; } else { nsp32_set_async(data, target); target->sync_flag |= SDTR_DONE; } nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "SDTR: entry: %d start_period: 0x%x offset: 0x%x\n", target->limit_entry, period, offset); } else if (target->sync_flag & SDTR_INITIATOR) { /* * It was negotiating SDTR with target, sending from the * initiator, but there are no chance to remove this flag. * Set async because we don't get proper negotiation. */ nsp32_set_async(data, target); target->sync_flag &= ~SDTR_INITIATOR; target->sync_flag |= SDTR_DONE; nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "SDTR_INITIATOR: fall back to async"); } else if (target->sync_flag & SDTR_TARGET) { /* * It was negotiating SDTR with target, sending from target, * but there are no chance to remove this flag. Set async * because we don't get proper negotiation. */ nsp32_set_async(data, target); target->sync_flag &= ~SDTR_TARGET; target->sync_flag |= SDTR_DONE; nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "Unknown SDTR from target is reached, fall back to async."); } nsp32_dbg(NSP32_DEBUG_TARGETFLAG, "target: %d sync_flag: 0x%x syncreg: 0x%x ackwidth: 0x%x", SCpnt->device->id, target->sync_flag, target->syncreg, target->ackwidth); /* Selection */ if (auto_param == 0) { ret = nsp32_selection_autopara(SCpnt); } else { ret = nsp32_selection_autoscsi(SCpnt); } if (ret != TRUE) { nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "selection fail"); nsp32_scsi_done(SCpnt); return SCSI_MLQUEUE_DEVICE_BUSY; } return 0;}/* initialize asic */static int nsp32hw_init(nsp32_hw_data *data){ unsigned int base = data->BaseAddress; unsigned short irq_stat; unsigned long lc_reg; unsigned char power; lc_reg = nsp32_index_read4(base, CFG_LATE_CACHE); if ((lc_reg & 0xff00) == 0) { lc_reg |= (0x20 << 8); nsp32_index_write2(base, CFG_LATE_CACHE, lc_reg & 0xffff); } nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); nsp32_write2(base, TRANSFER_CONTROL, 0); nsp32_write4(base, BM_CNT, 0); nsp32_write2(base, SCSI_EXECUTE_PHASE, 0); do { irq_stat = nsp32_read2(base, IRQ_STATUS); nsp32_dbg(NSP32_DEBUG_INIT, "irq_stat 0x%x", irq_stat); } while (irq_stat & IRQSTATUS_ANY_IRQ); /* * Fill FIFO_FULL_SHLD, FIFO_EMPTY_SHLD. Below parameter is * designated by specification. */ if ((data->trans_method & NSP32_TRANSFER_PIO) || (data->trans_method & NSP32_TRANSFER_MMIO)) { nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x40); nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x40); } else if (data->trans_method & NSP32_TRANSFER_BUSMASTER) { nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x10); nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x60); } else { nsp32_dbg(NSP32_DEBUG_INIT, "unknown transfer mode"); } nsp32_dbg(NSP32_DEBUG_INIT, "full 0x%x emp 0x%x", nsp32_index_read1(base, FIFO_FULL_SHLD_COUNT), nsp32_index_read1(base, FIFO_EMPTY_SHLD_COUNT)); nsp32_index_write1(base, CLOCK_DIV, data->clock); nsp32_index_write1(base, BM_CYCLE, MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD); nsp32_write1(base, PARITY_CONTROL, 0); /* parity check is disable */ /* * initialize MISC_WRRD register * * Note: Designated parameters is obeyed as following: * MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set. * MISC_MASTER_TERMINATION_SELECT: It must be set. * MISC_BMREQ_NEGATE_TIMING_SEL: It should be set. * MISC_AUTOSEL_TIMING_SEL: It should be set. * MISC_BMSTOP_CHANGE2_NONDATA_PHASE: It should be set. * MISC_DELAYED_BMSTART: It's selected for safety. * * Note: If MISC_BMSTOP_CHANGE2_NONDATA_PHASE is set, then * we have to set TRANSFERCONTROL_BM_START as 0 and set * appropriate value before restarting bus master transfer. */ nsp32_index_write2(base, MISC_WR, (SCSI_DIRECTION_DETECTOR_SELECT | DELAYED_BMSTART | MASTER_TERMINATION_SELECT | BMREQ_NEGATE_TIMING_SEL | AUTOSEL_TIMING_SEL | BMSTOP_CHANGE2_NONDATA_PHASE)); nsp32_index_write1(base, TERM_PWR_CONTROL, 0); power = nsp32_index_read1(base, TERM_PWR_CONTROL); if (!(power & SENSE)) { nsp32_msg(KERN_INFO, "term power on"); nsp32_index_write1(base, TERM_PWR_CONTROL, BPWR); } nsp32_write2(base, TIMER_SET, TIMER_STOP); nsp32_write2(base, TIMER_SET, TIMER_STOP); /* Required 2 times */ nsp32_write1(base, SYNC_REG, 0); nsp32_write1(base, ACK_WIDTH, 0); nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME); /* * enable to select designated IRQ (except for * IRQSELECT_SERR, IRQSELECT_PERR, IRQSELECT_BMCNTERR) */ nsp32_index_write2(base, IRQ_SELECT, IRQSELECT_TIMER_IRQ | IRQSELECT_SCSIRESET_IRQ | IRQSELECT_FIFO_SHLD_IRQ | IRQSELECT_RESELECT_IRQ | IRQSELECT_PHASE_CHANGE_IRQ | IRQSELECT_AUTO_SCSI_SEQ_IRQ | // IRQSELECT_BMCNTERR_IRQ | IRQSELECT_TARGET_ABORT_IRQ | IRQSELECT_MASTER_ABORT_IRQ ); nsp32_write2(base, IRQ_CONTROL, 0); /* PCI LED off */ nsp32_index_write1(base, EXT_PORT_DDR, LED_OFF); nsp32_index_write1(base, EXT_PORT, LED_OFF); return TRUE;}/* interrupt routine */static irqreturn_t do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs){ nsp32_hw_data *data = dev_id; unsigned int base = data->BaseAddress; Scsi_Cmnd *SCpnt = data->CurrentSC; unsigned short auto_stat, irq_stat, trans_stat; unsigned char busmon, busphase; unsigned long flags; int ret; int handled = 0;#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) struct Scsi_Host *host = data->Host; spin_lock_irqsave(host->host_lock, flags);#else spin_lock_irqsave(&io_request_lock, flags);#endif /* * IRQ check, then enable IRQ mask */ irq_stat = nsp32_read2(base, IRQ_STATUS); nsp32_dbg(NSP32_DEBUG_INTR, "enter IRQ: %d, IRQstatus: 0x%x", irq, irq_stat); /* is this interrupt comes from Ninja asic? */ if ((irq_stat & IRQSTATUS_ANY_IRQ) == 0) { nsp32_dbg(NSP32_DEBUG_INTR, "shared interrupt: irq other 0x%x", irq_stat); goto out2; } handled = 1; nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); busmon = nsp32_read1(base, SCSI_BUS_MONITOR); busphase = busmon & BUSMON_PHASE_MASK; trans_stat = nsp32_read2(base, TRANSFER_STATUS); if ((irq_stat == 0xffff) && (trans_stat == 0xffff)) { nsp32_msg(KERN_INFO, "card disconnect"); if (data->CurrentSC != NULL) { nsp32_msg(KERN_INFO, "clean up current SCSI command"); SCpnt->result = DID_BAD_TARGET << 16; nsp32_scsi_done(SCpnt); } goto out; } /* Timer IRQ */ if (irq_stat & IRQSTATUS_TIMER_IRQ) { nsp32_dbg(NSP32_DEBUG_INTR, "timer stop"); nsp32_write2(base, TIMER_SET, TIMER_STOP); goto out; } /* SCSI reset */ if (irq_stat & IRQSTATUS_SCSIRESET_IRQ) { nsp32_msg(KERN_INFO, "detected someone do bus reset"); nsp32_do_bus_reset(data); if (SCpnt != NULL) { SCpnt->result = DID_RESET << 16; nsp32_scsi_done(SCpnt); } goto out; } if (SCpnt == NULL) { nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happened"); nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat); goto out; } /* * AutoSCSI Interrupt. * Note: This interrupt is occurred when AutoSCSI is finished. Then * check SCSIEXECUTEPHASE, and do appropriate action. Each phases are * recorded when AutoSCSI sequencer has been processed. */ if(irq_stat & IRQSTATUS_AUTOSCSI_IRQ) { /* getting SCSI executed phase */ auto_stat = nsp32_read2(base, SCSI_EXECUTE_PHASE); nsp32_write2(base, SCSI_EXECUTE_PHASE, 0); /* Selection Timeout, go busfree phase. */ if (auto_stat & SELECTION_TIMEOUT) { nsp32_dbg(NSP32_DEBUG_INTR, "selection timeout occurred"); SCpnt->result = DID_TIME_OUT << 16; nsp32_scsi_done(SCpnt); goto out; } if (auto_stat & MSGOUT_PHASE) { /* * MsgOut phase was processed. * If MSG_IN_OCCUER is not set, then MsgOut phase is * completed. Thus, msgout_len must reset. Otherwise, * nothing to do here. If MSG_OUT_OCCUER is occurred, * then we will encounter the condition and check. */ if (!(auto_stat & MSG_IN_OCCUER) && (data->msgout_len <= 3)) { /* * !MSG_IN_OCCUER && msgout_len <=3 * ---> AutoSCSI with MSGOUTreg is processed. */ data->msgout_len = 0; }; nsp32_dbg(NSP32_DEBUG_INTR, "MsgOut phase processed"); } if ((auto_stat & DATA_IN_PHASE) && (SCpnt->resid > 0) && ((nsp32_read2(base, FIFO_REST_CNT) & FIFO_REST_MASK) != 0)) { printk( "auto+fifo\n"); //nsp32_pio_read(SCpnt); } if (auto_stat & (DATA_IN_PHASE | DATA_OUT_PHASE)) { /* DATA_IN_PHASE/DATA_OUT_PHASE was processed. */ nsp32_dbg(NSP32_DEBUG_INTR, "Data in/out phase processed"); /* read BMCNT, SGT pointer addr */ nsp32_dbg(NSP32_DEBUG_INTR, "BMCNT=0x%lx", nsp32_read4(base, BM_CNT)); nsp32_dbg(NSP32_DEBUG_INTR, "addr=0x%lx", nsp32_read4(base, SGT_ADR)); nsp32_dbg(NSP32_DEBUG_INTR, "SACK=0x%lx", nsp32_read4(base, SACK_CNT)); nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx", nsp32_read4(base, SAVED_SACK_CNT)); SCpnt->resid = 0; /* all data transfered! */ } /* * MsgIn Occur */ if (auto_stat & MSG_IN_OCCUER) { nsp32_msgin_occur(SCpnt, irq_stat, auto_stat); } /* * MsgOut Occur */ if (auto_stat & MSG_OUT_OCCUER) { nsp32_msgout_occur(SCpnt); } /* * Bus Free Occur */ if (auto_stat & BUS_FREE_OCCUER) { ret = nsp32_busfree_occur(SCpnt, auto_stat); if (ret == TRUE) { goto out; } } if (auto_stat & STATUS_PHASE) { /* * Read CSB and substitute CSB for SCpnt->result * to save status phase stutas byte. * scsi error handler checks host_byte (DID_*: * low level driver to indicate status), then checks * status_byte (SCSI status byte). */ SCpnt->result = (int)nsp32_read1(base, SCSI_CSB_IN); } if (auto_stat & ILLEGAL_PHASE) { /* Illegal phase is detected. SACK is not back. */ nsp32_msg(KERN_WARNING, "AUTO SCSI ILLEGAL PHASE OCCUR!!!!"); /* TODO: currently we don't have any action... bus reset? */ /* * To send back SACK, assert, wait, and negate. */ nsp32_sack_assert(data); nsp32_wait_req(data, NEGATE); nsp32_sack_negate(data); } if (auto_stat & COMMAND_PHASE) { /* nothing to do */ nsp32_dbg(NSP32_DEBUG_INTR, "Command phase processed"); } if (auto_stat & AUTOSCSI_BUSY) { /* AutoSCSI is running */ } show_autophase(auto_stat); } /* FIFO_SHLD_IRQ */ if (irq_stat & IRQSTATUS_FIFO_SHLD_IRQ) { nsp32_dbg(NSP32_DEBUG_INTR, "FIFO IRQ"); switch(busphase) { case BUSPHASE_DATA_OUT: nsp32_dbg(NSP32_DEBUG_INTR, "fifo/write"); //nsp32_pio_write(SCpnt); break; case BUSPHASE_DATA_IN: nsp32_dbg(NSP32_DEBUG_INTR, "fifo/read"); //nsp32_pio_read(SCpnt); break; case BUSPHASE_STATUS: nsp32_dbg(NSP32_DEBUG_INTR, "fifo/status"); SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); break; default: nsp32_dbg(NSP32_DEBUG_INTR, "fifo/other phase"); nsp32_dbg(NSP32_DEBUG_INTR, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat); show_busphase(busphase); break; } goto out; } /* Phase Change IRQ */ if (irq_stat & IRQSTATUS_PHASE_CHANGE_IRQ) { nsp32_dbg(NSP32_DEBUG_INTR, "phase change IRQ"); switch(busphase) { case BUSPHASE_MESSAGE_IN: nsp32_dbg(NSP32_DEBUG_INTR, "phase chg/msg in"); nsp32_msgin_occur(SCpnt, irq_stat, 0); break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?