📄 nsp_cs.c
字号:
{0x5, 2, 0x20, 0x25}, /* 7.5 : 150ns, 75ns */ {0x6, 2, 0x26, 0x31}, /* 5.71: 175ns, 75ns */ {0x7, 3, 0x32, 0x32}, /* 5.0 : 200ns, 100ns */ {0x8, 3, 0x33, 0x38}, /* 4.44: 225ns, 100ns */ {0x9, 3, 0x39, 0x3e}, /* 4.0 : 250ns, 100ns */ {0xa, 3, 0x3f, 0x44}, /* 3.64: 275ns, 100ns */ {0xb, 3, 0x45, 0x4b}, /* 3.33: 300ns, 100ns */ {0xc, 3, 0x4c, 0x53}, /* 3.01: 325ns, 100ns */ {0xd, 3, 0x54, 0x57}, /* 2.86: 350ns, 100ns */ {0xe, 3, 0x58, 0x5d}, /* 2.67: 375ns, 100ns */ {0xf, 3, 0x5e, 0x64}, /* 2.5 : 400ns, 100ns */ {0,0,0,0},};static struct nsp_sync_table nsp_sync_table_20M[] = { {0x1, 0, 0x19, 0x19}, /* 10.0 : 100ns, 50ns */ {0x2, 0, 0x1a, 0x25}, /* 6.7 : 150ns, 50ns */ {0x3, 1, 0x26, 0x32}, /* 5.0 : 200ns, 100ns */ {0x4, 1, 0x33, 0x3e}, /* 4.0 : 250ns, 100ns */ {0x5, 2, 0x3f, 0x4b}, /* 3.3 : 300ns, 150ns */ {0x6, 2, 0x4c, 0x57}, /* 2.8 : 350ns, 150ns */ {0x7, 3, 0x58, 0x64}, /* 2.5 : 400ns, 200ns */ {0x8, 3, 0x65, 0x70}, /* 2.2 : 450ns, 200ns */ {0x9, 3, 0x71, 0x7d}, /* 2.0 : 500ns, 200ns */ {0xa, 3, 0x7e, 0x89}, /* 1.82: 550ns, 200ns */ {0xb, 3, 0x8a, 0x95}, /* 1.67: 550ns, 200ns */ {0xc, 3, 0x96, 0xa2}, /* 1.54: 550ns, 200ns */ {0xd, 3, 0xa3, 0xae}, /* 1.43: 550ns, 200ns */ {0xe, 3, 0xaf, 0xbb}, /* 1.33: 550ns, 200ns */ {0xf, 3, 0xbc, 0xc8}, /* 1.25: 550ns, 200ns */ {0,0,0,0},};/* * setup synchronous data transfer mode */static int nsp_analyze_sdtr(Scsi_Cmnd *SCpnt){ 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]); struct nsp_sync_table *sync_table; unsigned int period, offset; int i; nsp_dbg(NSP_DEBUG_SYNC, "in"); period = sync->SyncPeriod; offset = sync->SyncOffset; nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset); switch (data->ScsiClockDiv) { case CLOCK_20M: case CLOCK_40M: sync_table = nsp_sync_table_20M; break; case CLOCK_40M | FAST_20: sync_table = nsp_sync_table_40M; break; default: nsp_msg(KERN_WARNING, "Invalid clock div is selected, set 20M."); sync_table = nsp_sync_table_20M; break; } for ( i = 0; sync_table->max_period != 0; i++, sync_table++) { if ( period >= sync_table->min_period && period <= sync_table->max_period ) { break; } } if (period != 0 && sync_table->max_period == 0) { /* * No proper period/offset found */ nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset"); sync->SyncPeriod = 0; sync->SyncOffset = 0; sync->SyncRegister = 0; sync->AckWidth = 0; return FALSE; } sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) | (offset & SYNCREG_OFFSET_MASK); sync->AckWidth = sync_table->ack_width; nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth); return TRUE;}/* * start ninja hardware timer */static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time){ unsigned int base = SCpnt->device->host->io_port; nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time); data->TimerCount = time; nsp_index_write(base, TIMERCOUNT, time);}/* * wait for bus phase change */static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str){ unsigned int base = SCpnt->device->host->io_port; unsigned char reg; int time_out; //nsp_dbg(NSP_DEBUG_INTR, "in"); time_out = 100; do { reg = nsp_index_read(base, SCSIBUSMON); if (reg == 0xff) { break; } } while ((time_out-- != 0) && (reg & mask) != 0); if (time_out == 0) { nsp_msg(KERN_DEBUG, " %s signal off timeut", str); } return 0;}/* * 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 = SG_ADDRESS(SCpnt->SCp.buffer); 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -