nsp32.c
来自「linux 内核源代码」· C语言 代码 · 共 2,411 行 · 第 1/5 页
C
2,411 行
if(length > (pos - buffer)) { \ pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \ nsp32_dbg(NSP32_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\ } \ } while(0)static int nsp32_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout){ char *pos = buffer; int thislength; unsigned long flags; nsp32_hw_data *data; int hostno; unsigned int base; unsigned char mode_reg; int id, speed; long model; /* Write is not supported, just return. */ if (inout == TRUE) { return -EINVAL; } hostno = host->host_no; data = (nsp32_hw_data *)host->hostdata; base = host->io_port; SPRINTF("NinjaSCSI-32 status\n\n"); SPRINTF("Driver version: %s, $Revision: 1.33 $\n", nsp32_release_version); SPRINTF("SCSI host No.: %d\n", hostno); SPRINTF("IRQ: %d\n", host->irq); SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1); SPRINTF("sg_tablesize: %d\n", host->sg_tablesize); SPRINTF("Chip revision: 0x%x\n", (nsp32_read2(base, INDEX_REG) >> 8) & 0xff); mode_reg = nsp32_index_read1(base, CHIP_MODE); model = data->pci_devid->driver_data;#ifdef CONFIG_PM SPRINTF("Power Management: %s\n", (mode_reg & OPTF) ? "yes" : "no");#endif SPRINTF("OEM: %ld, %s\n", (mode_reg & (OEM0|OEM1)), nsp32_model[model]); spin_lock_irqsave(&(data->Lock), flags); SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC); spin_unlock_irqrestore(&(data->Lock), flags); SPRINTF("SDTR status\n"); for (id = 0; id < ARRAY_SIZE(data->target); id++) { SPRINTF("id %d: ", id); if (id == host->this_id) { SPRINTF("----- NinjaSCSI-32 host adapter\n"); continue; } if (data->target[id].sync_flag == SDTR_DONE) { if (data->target[id].period == 0 && data->target[id].offset == ASYNC_OFFSET ) { SPRINTF("async"); } else { SPRINTF(" sync"); } } else { SPRINTF(" none"); } if (data->target[id].period != 0) { speed = 1000000 / (data->target[id].period * 4); SPRINTF(" transfer %d.%dMB/s, offset %d", speed / 1000, speed % 1000, data->target[id].offset ); } SPRINTF("\n"); } thislength = pos - (buffer + offset); if(thislength < 0) { *start = NULL; return 0; } thislength = min(thislength, length); *start = buffer + offset; return thislength;}#undef SPRINTF/* * Reset parameters and call scsi_done for data->cur_lunt. * Be careful setting SCpnt->result = DID_* before calling this function. */static void nsp32_scsi_done(struct scsi_cmnd *SCpnt){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsigned int base = SCpnt->device->host->io_port; scsi_dma_unmap(SCpnt); /* * clear TRANSFERCONTROL_BM_START */ nsp32_write2(base, TRANSFER_CONTROL, 0); nsp32_write4(base, BM_CNT, 0); /* * call scsi_done */ (*SCpnt->scsi_done)(SCpnt); /* * reset parameters */ data->cur_lunt->SCpnt = NULL; data->cur_lunt = NULL; data->cur_target = NULL; data->CurrentSC = NULL;}/* * Bus Free Occur * * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase * with ACK reply when below condition is matched: * MsgIn 00: Command Complete. * MsgIn 02: Save Data Pointer. * MsgIn 04: Diconnect. * In other case, unexpected BUSFREE is detected. */static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsigned int base = SCpnt->device->host->io_port; nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter execph=0x%x", execph); show_autophase(execph); nsp32_write4(base, BM_CNT, 0); nsp32_write2(base, TRANSFER_CONTROL, 0); /* * MsgIn 02: Save Data Pointer * * VALID: * Save Data Pointer is received. Adjust pointer. * * NO-VALID: * SCSI-3 says if Save Data Pointer is not received, then we restart * processing and we can't adjust any SCSI data pointer in next data * phase. */ if (execph & MSGIN_02_VALID) { nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid"); /* * Check sack_cnt/saved_sack_cnt, then adjust sg table if * needed. */ if (!(execph & MSGIN_00_VALID) && ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) { unsigned int sacklen, s_sacklen; /* * Read SACK count and SAVEDSACK count, then compare. */ sacklen = nsp32_read4(base, SACK_CNT ); s_sacklen = nsp32_read4(base, SAVED_SACK_CNT); /* * If SAVEDSACKCNT == 0, it means SavedDataPointer is * come after data transfering. */ if (s_sacklen > 0) { /* * Comparing between sack and savedsack to * check the condition of AutoMsgIn03. * * If they are same, set msgin03 == TRUE, * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at * reselection. On the other hand, if they * aren't same, set msgin03 == FALSE, and * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at * reselection. */ if (sacklen != s_sacklen) { data->cur_lunt->msgin03 = FALSE; } else { data->cur_lunt->msgin03 = TRUE; } nsp32_adjust_busfree(SCpnt, s_sacklen); } } /* This value has not substitude with valid value yet... */ //data->cur_lunt->save_datp = data->cur_datp; } else { /* * no processing. */ } if (execph & MSGIN_03_VALID) { /* MsgIn03 was valid to be processed. No need processing. */ } /* * target SDTR check */ if (data->cur_target->sync_flag & SDTR_INITIATOR) { /* * SDTR negotiation pulled by the initiator has not * finished yet. Fall back to ASYNC mode. */ nsp32_set_async(data, data->cur_target); data->cur_target->sync_flag &= ~SDTR_INITIATOR; data->cur_target->sync_flag |= SDTR_DONE; } else if (data->cur_target->sync_flag & SDTR_TARGET) { /* * SDTR negotiation pulled by the target has been * negotiating. */ if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) { /* * If valid message is received, then * negotiation is succeeded. */ } else { /* * On the contrary, if unexpected bus free is * occurred, then negotiation is failed. Fall * back to ASYNC mode. */ nsp32_set_async(data, data->cur_target); } data->cur_target->sync_flag &= ~SDTR_TARGET; data->cur_target->sync_flag |= SDTR_DONE; } /* * It is always ensured by SCSI standard that initiator * switches into Bus Free Phase after * receiving message 00 (Command Complete), 04 (Disconnect). * It's the reason that processing here is valid. */ if (execph & MSGIN_00_VALID) { /* MsgIn 00: Command Complete */ nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete"); SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); SCpnt->SCp.Message = 0; nsp32_dbg(NSP32_DEBUG_BUSFREE, "normal end stat=0x%x resid=0x%x\n", SCpnt->SCp.Status, scsi_get_resid(SCpnt)); SCpnt->result = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0); nsp32_scsi_done(SCpnt); /* All operation is done */ return TRUE; } else if (execph & MSGIN_04_VALID) { /* MsgIn 04: Disconnect */ SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); SCpnt->SCp.Message = 4; nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect"); return TRUE; } else { /* Unexpected bus free */ nsp32_msg(KERN_WARNING, "unexpected bus free occurred"); /* DID_ERROR? */ //SCpnt->result = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0); SCpnt->result = DID_ERROR << 16; nsp32_scsi_done(SCpnt); return TRUE; } return FALSE;}/* * nsp32_adjust_busfree - adjusting SG table * * Note: This driver adjust the SG table using SCSI ACK * counter instead of BMCNT counter! */static void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; int old_entry = data->cur_entry; int new_entry; int sg_num = data->cur_lunt->sg_num; nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt; unsigned int restlen, sentlen; u32_le len, addr; nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", scsi_get_resid(SCpnt)); /* adjust saved SACK count with 4 byte start address boundary */ s_sacklen -= le32_to_cpu(sgt[old_entry].addr) & 3; /* * calculate new_entry from sack count and each sgt[].len * calculate the byte which is intent to send */ sentlen = 0; for (new_entry = old_entry; new_entry < sg_num; new_entry++) { sentlen += (le32_to_cpu(sgt[new_entry].len) & ~SGTEND); if (sentlen > s_sacklen) { break; } } /* all sgt is processed */ if (new_entry == sg_num) { goto last; } if (sentlen == s_sacklen) { /* XXX: confirm it's ok or not */ /* In this case, it's ok because we are at the head element of the sg. restlen is correctly calculated. */ } /* calculate the rest length for transfering */ restlen = sentlen - s_sacklen; /* update adjusting current SG table entry */ len = le32_to_cpu(sgt[new_entry].len); addr = le32_to_cpu(sgt[new_entry].addr); addr += (len - restlen); sgt[new_entry].addr = cpu_to_le32(addr); sgt[new_entry].len = cpu_to_le32(restlen); /* set cur_entry with new_entry */ data->cur_entry = new_entry; return; last: if (scsi_get_resid(SCpnt) < sentlen) { nsp32_msg(KERN_ERR, "resid underflow"); } scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) - sentlen); nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", scsi_get_resid(SCpnt)); /* update hostdata and lun */ return;}/* * It's called MsgOut phase occur. * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in * message out phase. It, however, has more than 3 messages, * HBA creates the interrupt and we have to process by hand. */static void nsp32_msgout_occur(struct scsi_cmnd *SCpnt){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsigned int base = SCpnt->device->host->io_port; //unsigned short command; long new_sgtp; int i; nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "enter: msgout_len: 0x%x", data->msgout_len); /* * If MsgOut phase is occurred without having any * message, then No_Operation is sent (SCSI-2). */ if (data->msgout_len == 0) { nsp32_build_nop(SCpnt); } /* * Set SGTP ADDR current entry for restarting AUTOSCSI, * because SGTP is incremented next point. * There is few statement in the specification... */ new_sgtp = data->cur_lunt->sglun_paddr + (data->cur_lunt->cur_entry * sizeof(nsp32_sgtable)); /* * send messages */ for (i = 0; i < data->msgout_len; i++) { nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "%d : 0x%x", i, data->msgoutbuf[i]); /* * Check REQ is asserted. */ nsp32_wait_req(data, ASSERT); if (i == (data->msgout_len - 1)) { /* * If the last message, set the AutoSCSI restart * before send back the ack message. AutoSCSI * restart automatically negate ATN signal. */ //command = (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02); //nsp32_restart_autoscsi(SCpnt, command); nsp32_write2(base, COMMAND_CONTROL, (CLEAR_CDB_FIFO_POINTER | AUTO_COMMAND_PHASE | AUTOSCSI_RESTART | AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02 )); } /* * Write data with SACK, then wait sack is * automatically negated. */ nsp32_write1(base, SCSI_DATA_WITH_ACK, data->msgoutbuf[i]); nsp32_wait_sack(data, NEGATE); nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "bus: 0x%x\n", nsp32_read1(base, SCSI_BUS_MONITOR)); }; data->msgout_len = 0; nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "exit");}/* * Restart AutoSCSI * * Note: Restarting AutoSCSI needs set: * SYNC_REG, ACK_WIDTH, SGT_ADR, TRANSFER_CONTROL */static void nsp32_restart_autoscsi(struct scsi_cmnd *SCpnt, unsigned short command){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsigned int base = data->BaseAddress; unsigned short transfer = 0; nsp32_dbg(NSP32_DEBUG_RESTART, "enter"); if (data->cur_target == NULL || data->cur_lunt == NULL) { nsp32_msg(KERN_ERR, "Target or Lun is invalid"); } /* * set SYNC_REG * Don't set BM_START_ADR before setting this register. */ nsp32_write1(base, SYNC_REG, data->cur_target->syncreg); /* * set ACKWIDTH */ nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth); /* * set SREQ hazard killer sampling rate */ nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg); /* * set SGT ADDR (physical address) */ nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?