📄 nsp_cs.c
字号:
/* * expect Ninja Irq */static int nsp_expect_signal(Scsi_Cmnd *SCpnt, unsigned char current_phase, unsigned char mask){ unsigned int base = SCpnt->device->host->io_port; int time_out; unsigned char phase, i_src; //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask); time_out = 100; do { phase = nsp_index_read(base, SCSIBUSMON); if (phase == 0xff) { //nsp_dbg(NSP_DEBUG_INTR, "ret -1"); return -1; } i_src = nsp_read(base, IRQSTATUS); if (i_src & IRQSTATUS_SCSI) { //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal"); return 0; } if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) { //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase); return 1; } } while(time_out-- != 0); //nsp_dbg(NSP_DEBUG_INTR, "timeout"); return -1;}/* * transfer SCSI message */static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase){ unsigned int base = SCpnt->device->host->io_port; nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; char *buf = data->MsgBuffer; int len = min(MSGBUF_SIZE, data->MsgLen); int ptr; int ret; //nsp_dbg(NSP_DEBUG_DATA_IO, "in"); for (ptr = 0; len > 0; len--, ptr++) { ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ); if (ret <= 0) { nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit"); return 0; } /* if last byte, negate ATN */ if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) { nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB); } /* read & write message */ if (phase & BUSMON_IO) { nsp_dbg(NSP_DEBUG_DATA_IO, "read msg"); buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK); } else { nsp_dbg(NSP_DEBUG_DATA_IO, "write msg"); nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]); } nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>"); } return len;}/* * get extra SCSI data from fifo */static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt){ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; unsigned int count; //nsp_dbg(NSP_DEBUG_DATA_IO, "in"); if (SCpnt->SCp.have_data_in != IO_IN) { return 0; } count = nsp_fifo_count(SCpnt); if (data->FifoCount == count) { //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk"); return 0; } /* * XXX: NSP_QUIRK * data phase skip only occures in case of SCSI_LOW_READ */ nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk"); SCpnt->SCp.phase = PH_DATA; nsp_pio_read(SCpnt); nsp_setup_fifo(data, FALSE); return 0;}/* * accept reselection */static int nsp_reselected(Scsi_Cmnd *SCpnt){ unsigned int base = SCpnt->device->host->io_port; unsigned int host_id = SCpnt->device->host->this_id; //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; unsigned char bus_reg; unsigned char id_reg, tmp; int target; nsp_dbg(NSP_DEBUG_RESELECTION, "in"); id_reg = nsp_index_read(base, RESELECTID); tmp = id_reg & (~BIT(host_id)); target = 0; while(tmp != 0) { if (tmp & BIT(0)) { break; } tmp >>= 1; target++; } if (SCpnt->device->id != target) { nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target); } nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>"); nsp_nexus(SCpnt); bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN); nsp_index_write(base, SCSIBUSCTRL, bus_reg); nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB); return TRUE;}/* * count how many data transferd */static int nsp_fifo_count(Scsi_Cmnd *SCpnt){ unsigned int base = SCpnt->device->host->io_port; unsigned int count; unsigned int l, m, h, dummy; nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER); l = nsp_index_read(base, TRANSFERCOUNT); m = nsp_index_read(base, TRANSFERCOUNT); h = nsp_index_read(base, TRANSFERCOUNT); dummy = nsp_index_read(base, TRANSFERCOUNT); /* required this! */ count = (h << 16) | (m << 8) | (l << 0); //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count); return count;}/* fifo size */#define RFIFO_CRIT 64#define WFIFO_CRIT 64/* * read data in DATA IN phase */static void nsp_pio_read(Scsi_Cmnd *SCpnt){ unsigned int base = SCpnt->device->host->io_port; unsigned long mmio_base = SCpnt->device->host->base; nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; long time_out; int ocount, res; unsigned char stat, fifo_stat; ocount = data->FifoCount; nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d", SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual); time_out = 1000; while ((time_out-- != 0) && (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) { stat = nsp_index_read(base, SCSIBUSMON); stat &= BUSMON_PHASE_MASK; res = nsp_fifo_count(SCpnt) - ocount; //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x ocount=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res); if (res == 0) { /* if some data avilable ? */ if (stat == BUSPHASE_DATA_IN) { /* phase changed? */ //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual); continue; } else { nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat); break; } } fifo_stat = nsp_read(base, FIFOSTATUS); if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 && stat == BUSPHASE_DATA_IN) { continue; } res = min(res, SCpnt->SCp.this_residual); switch (data->TransferMode) { case MODE_IO32: res &= ~(BIT(1)|BIT(0)); /* align 4 */ nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2); break; case MODE_IO8: nsp_fifo8_read (base, SCpnt->SCp.ptr, res ); break; case MODE_MEM32: res &= ~(BIT(1)|BIT(0)); /* align 4 */ nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2); break; default: nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode"); return; } SCpnt->resid -= res; SCpnt->SCp.ptr += res; SCpnt->SCp.this_residual -= res; ocount += res; //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount); /* go to next scatter list if available */ if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.buffers_residual != 0 ) { //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out); SCpnt->SCp.buffers_residual--; SCpnt->SCp.buffer++; SCpnt->SCp.ptr = BUFFER_ADDR; SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; time_out = 1000; //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset); } } data->FifoCount = ocount; if (time_out == 0) { nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d", SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); } nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount); nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);}/* * write data in DATA OUT phase */static void nsp_pio_write(Scsi_Cmnd *SCpnt){ unsigned int base = SCpnt->device->host->io_port; unsigned long mmio_base = SCpnt->device->host->base; nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; int time_out; int ocount, res; unsigned char stat; ocount = data->FifoCount; nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x", data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid); time_out = 1000; while ((time_out-- != 0) && (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) { stat = nsp_index_read(base, SCSIBUSMON); stat &= BUSMON_PHASE_MASK; if (stat != BUSPHASE_DATA_OUT) { res = ocount - nsp_fifo_count(SCpnt); nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res); /* Put back pointer */ SCpnt->resid += res; SCpnt->SCp.ptr -= res; SCpnt->SCp.this_residual += res; ocount -= res; break; } res = ocount - nsp_fifo_count(SCpnt); if (res > 0) { /* write all data? */ nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res); continue; } res = min(SCpnt->SCp.this_residual, WFIFO_CRIT); //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); switch (data->TransferMode) { case MODE_IO32: res &= ~(BIT(1)|BIT(0)); /* align 4 */ nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2); break; case MODE_IO8: nsp_fifo8_write (base, SCpnt->SCp.ptr, res ); break; case MODE_MEM32: res &= ~(BIT(1)|BIT(0)); /* align 4 */ nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2); break; default: nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode"); break; } SCpnt->resid -= res; SCpnt->SCp.ptr += res; SCpnt->SCp.this_residual -= res; ocount += res; /* go to next scatter list if available */ if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.buffers_residual != 0 ) { //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next"); SCpnt->SCp.buffers_residual--; SCpnt->SCp.buffer++; SCpnt->SCp.ptr = BUFFER_ADDR; SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; time_out = 1000; } } data->FifoCount = ocount; if (time_out == 0) { nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid); } nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount); nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);}#undef RFIFO_CRIT#undef WFIFO_CRIT/* * setup synchronous/asynchronous data transfer mode */static int nsp_nexus(Scsi_Cmnd *SCpnt){ unsigned int base = SCpnt->device->host->io_port; unsigned char target = SCpnt->device->id;// unsigned char lun = SCpnt->device->lun; nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; sync_data *sync = &(data->Sync[target]); //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt); /* setup synch transfer registers */ nsp_index_write(base, SYNCREG, sync->SyncRegister); nsp_index_write(base, ACKWIDTH, sync->AckWidth); if (SCpnt->use_sg == 0 || SCpnt->resid % 4 != 0 || SCpnt->resid <= PAGE_SIZE ) { data->TransferMode = MODE_IO8; } else if (nsp_burst_mode == BURST_MEM32) { data->TransferMode = MODE_MEM32; } else if (nsp_burst_mode == BURST_IO32) { data->TransferMode = MODE_IO32; } else { data->TransferMode = MODE_IO8; } /* setup pdma fifo */ nsp_setup_fifo(data, TRUE); /* clear ack counter */ data->FifoCount = 0; nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER_CLEAR | REQ_COUNTER_CLEAR | HOST_COUNTER_CLEAR); return 0;}#include "nsp_message.c"/* * interrupt handler */static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs){ unsigned int base; unsigned char irq_status, irq_phase, phase; Scsi_Cmnd *tmpSC; unsigned char target, lun; unsigned int *sync_neg; int i, tmp; nsp_hw_data *data; //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id); //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host); if ( dev_id != NULL && ((scsi_info_t *)dev_id)->host != NULL ) { scsi_info_t *info = (scsi_info_t *)dev_id; data = (nsp_hw_data *)info->host->hostdata; } else { nsp_dbg(NSP_DEBUG_INTR, "host data wrong"); return IRQ_NONE; } //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id); base = data->BaseAddress; //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base); /* * interrupt check */ nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE); irq_status = nsp_read(base, IRQSTATUS); //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status); if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) { nsp_write(base, IRQCONTROL, 0); //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq"); return IRQ_NONE; } /* XXX: IMPORTANT * Do not read an irq_phase register if no scsi phase interrupt. * Unless, you should lose a scsi phase interrupt. */ phase = nsp_index_read(base, SCSIBUSMON); if((irq_status & IRQSTATUS_SCSI) != 0) { irq_phase = nsp_index_read(base, IRQPHASESENCE); } else { irq_phase = 0; } //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase); /* * timer interrupt handler (scsi vs timer interrupts) */ //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount); if (data->TimerCount != 0) { //nsp_dbg(NSP_DEBUG_INTR, "stop timer"); nsp_index_write(base, TIMERCOUNT, 0); nsp_index_write(base, TIMERCOUNT, 0); data->TimerCount = 0; } if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER && data->SelectionTimeOut == 0) { //nsp_dbg(NSP_DEBUG_INTR, "timer start"); nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR); return IRQ_HANDLED; } nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR); if ((irq_status & IRQSTATUS_SCSI) && (irq_phase & SCSI_RESET_IRQ)) { nsp_msg(KERN_ERR, "bus reset (power off?)"); nsphw_init(data); nsp_bus_reset(data); if(data->CurrentSC != NULL) { tmpSC = data->CurrentSC; tmpSC->result = (DID_RESET << 16) | ((tmpSC->SCp.Message & 0xff) << 8) | ((tmpSC->SCp.Status & 0xff) << 0); nsp_scsi_done(tmpSC); } return IRQ_HANDLED; } if (data->CurrentSC == NULL) { nsp_msg(KERN_ERR, "CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen. reset everything", irq_status, phase, irq_phase); nsphw_init(data); nsp_bus_reset(data); return IRQ_HANDLED; } tmpSC = data->CurrentSC; target = tmpSC->device->id; lun = tmpSC->device->lun; sync_neg = &(data->Sync[target].SyncNegotiation); /* * parse hardware SCSI irq reasons register */ if (irq_status & IRQSTATUS_SCSI) { if (irq_phase & RESELECT_IRQ) { nsp_dbg(NSP_DEBUG_INTR, "reselect"); nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR); if (nsp_reselected(tmpSC) != FALSE) { return IRQ_HANDLED; } } if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) { return IRQ_HANDLED; } } //show_phase(tmpSC); switch(tmpSC->SCp.phase) { case PH_SELSTART: // *sync_neg = SYNC_NOT_YET; if ((phase & BUSMON_BSY) == 0) { //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut); if (data->SelectionTimeOut >= NSP_SELTIMEOUT) { nsp_dbg(NSP_DEBUG_INTR, "selection time out"); data->SelectionTimeOut = 0; nsp_index_write(base, SCSIBUSCTRL, 0); tmpSC->result = DID_TIME_OUT << 16; nsp_scsi_done(tmpSC); return IRQ_HANDLED; } data->SelectionTimeOut += 1; nsp_start_timer(tmpSC, 1000/51); return IRQ_HANDLED; } /* attention assert */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -