nsp32.c
来自「linux 内核源代码」· C语言 代码 · 共 2,411 行 · 第 1/5 页
C
2,411 行
/* * set TRANSFER CONTROL REG */ transfer = 0; transfer |= (TRANSFER_GO | ALL_COUNTER_CLR); if (data->trans_method & NSP32_TRANSFER_BUSMASTER) { if (scsi_bufflen(SCpnt) > 0) { transfer |= BM_START; } } else if (data->trans_method & NSP32_TRANSFER_MMIO) { transfer |= CB_MMIO_MODE; } else if (data->trans_method & NSP32_TRANSFER_PIO) { transfer |= CB_IO_MODE; } nsp32_write2(base, TRANSFER_CONTROL, transfer); /* * restart AutoSCSI * * TODO: COMMANDCONTROL_AUTO_COMMAND_PHASE is needed ? */ command |= (CLEAR_CDB_FIFO_POINTER | AUTO_COMMAND_PHASE | AUTOSCSI_RESTART ); nsp32_write2(base, COMMAND_CONTROL, command); nsp32_dbg(NSP32_DEBUG_RESTART, "exit");}/* * cannot run automatically message in occur */static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt, unsigned long irq_status, unsigned short execph){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsigned int base = SCpnt->device->host->io_port; unsigned char msg; unsigned char msgtype; unsigned char newlun; unsigned short command = 0; int msgclear = TRUE; long new_sgtp; int ret; /* * read first message * Use SCSIDATA_W_ACK instead of SCSIDATAIN, because the procedure * of Message-In have to be processed before sending back SCSI ACK. */ msg = nsp32_read1(base, SCSI_DATA_IN); data->msginbuf[(unsigned char)data->msgin_len] = msg; msgtype = data->msginbuf[0]; nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter: msglen: 0x%x msgin: 0x%x msgtype: 0x%x", data->msgin_len, msg, msgtype); /* * TODO: We need checking whether bus phase is message in? */ /* * assert SCSI ACK */ nsp32_sack_assert(data); /* * processing IDENTIFY */ if (msgtype & 0x80) { if (!(irq_status & IRQSTATUS_RESELECT_OCCUER)) { /* Invalid (non reselect) phase */ goto reject; } newlun = msgtype & 0x1f; /* TODO: SPI-3 compliant? */ ret = nsp32_reselection(SCpnt, newlun); if (ret == TRUE) { goto restart; } else { goto reject; } } /* * processing messages except for IDENTIFY * * TODO: Messages are all SCSI-2 terminology. SCSI-3 compliance is TODO. */ switch (msgtype) { /* * 1-byte message */ case COMMAND_COMPLETE: case DISCONNECT: /* * These messages should not be occurred. * They should be processed on AutoSCSI sequencer. */ nsp32_msg(KERN_WARNING, "unexpected message of AutoSCSI MsgIn: 0x%x", msg); break; case RESTORE_POINTERS: /* * AutoMsgIn03 is disabled, and HBA gets this message. */ if ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE)) { unsigned int s_sacklen; s_sacklen = nsp32_read4(base, SAVED_SACK_CNT); if ((execph & MSGIN_02_VALID) && (s_sacklen > 0)) { nsp32_adjust_busfree(SCpnt, s_sacklen); } else { /* No need to rewrite SGT */ } } data->cur_lunt->msgin03 = FALSE; /* Update with the new value */ /* reset SACK/SavedACK counter (or ALL clear?) */ nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK); /* * set new sg pointer */ new_sgtp = data->cur_lunt->sglun_paddr + (data->cur_lunt->cur_entry * sizeof(nsp32_sgtable)); nsp32_write4(base, SGT_ADR, new_sgtp); break; case SAVE_POINTERS: /* * These messages should not be occurred. * They should be processed on AutoSCSI sequencer. */ nsp32_msg (KERN_WARNING, "unexpected message of AutoSCSI MsgIn: SAVE_POINTERS"); break; case MESSAGE_REJECT: /* If previous message_out is sending SDTR, and get message_reject from target, SDTR negotiation is failed */ if (data->cur_target->sync_flag & (SDTR_INITIATOR | SDTR_TARGET)) { /* * Current target is negotiating SDTR, but it's * failed. Fall back to async transfer mode, and set * SDTR_DONE. */ nsp32_set_async(data, data->cur_target); data->cur_target->sync_flag &= ~SDTR_INITIATOR; data->cur_target->sync_flag |= SDTR_DONE; } break; case LINKED_CMD_COMPLETE: case LINKED_FLG_CMD_COMPLETE: /* queue tag is not supported currently */ nsp32_msg (KERN_WARNING, "unsupported message: 0x%x", msgtype); break; case INITIATE_RECOVERY: /* staring ECA (Extended Contingent Allegiance) state. */ /* This message is declined in SPI2 or later. */ goto reject; /* * 2-byte message */ case SIMPLE_QUEUE_TAG: case 0x23: /* * 0x23: Ignore_Wide_Residue is not declared in scsi.h. * No support is needed. */ if (data->msgin_len >= 1) { goto reject; } /* current position is 1-byte of 2 byte */ msgclear = FALSE; break; /* * extended message */ case EXTENDED_MESSAGE: if (data->msgin_len < 1) { /* * Current position does not reach 2-byte * (2-byte is extended message length). */ msgclear = FALSE; break; } if ((data->msginbuf[1] + 1) > data->msgin_len) { /* * Current extended message has msginbuf[1] + 2 * (msgin_len starts counting from 0, so buf[1] + 1). * If current message position is not finished, * continue receiving message. */ msgclear = FALSE; break; } /* * Reach here means regular length of each type of * extended messages. */ switch (data->msginbuf[2]) { case EXTENDED_MODIFY_DATA_POINTER: /* TODO */ goto reject; /* not implemented yet */ break; case EXTENDED_SDTR: /* * Exchange this message between initiator and target. */ if (data->msgin_len != EXTENDED_SDTR_LEN + 1) { /* * received inappropriate message. */ goto reject; break; } nsp32_analyze_sdtr(SCpnt); break; case EXTENDED_EXTENDED_IDENTIFY: /* SCSI-I only, not supported. */ goto reject; /* not implemented yet */ break; case EXTENDED_WDTR: goto reject; /* not implemented yet */ break; default: goto reject; } break; default: goto reject; } restart: if (msgclear == TRUE) { data->msgin_len = 0; /* * If restarting AutoSCSI, but there are some message to out * (msgout_len > 0), set AutoATN, and set SCSIMSGOUT as 0 * (MV_VALID = 0). When commandcontrol is written with * AutoSCSI restart, at the same time MsgOutOccur should be * happened (however, such situation is really possible...?). */ if (data->msgout_len > 0) { nsp32_write4(base, SCSI_MSG_OUT, 0); command |= AUTO_ATN; } /* * restart AutoSCSI * If it's failed, COMMANDCONTROL_AUTO_COMMAND_PHASE is needed. */ command |= (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02); /* * If current msgin03 is TRUE, then flag on. */ if (data->cur_lunt->msgin03 == TRUE) { command |= AUTO_MSGIN_03; } data->cur_lunt->msgin03 = FALSE; } else { data->msgin_len++; } /* * restart AutoSCSI */ nsp32_restart_autoscsi(SCpnt, command); /* * wait SCSI REQ negate for REQ-ACK handshake */ nsp32_wait_req(data, NEGATE); /* * negate SCSI ACK */ nsp32_sack_negate(data); nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit"); return; reject: nsp32_msg(KERN_WARNING, "invalid or unsupported MessageIn, rejected. " "current msg: 0x%x (len: 0x%x), processing msg: 0x%x", msg, data->msgin_len, msgtype); nsp32_build_reject(SCpnt); data->msgin_len = 0; goto restart;}/* * */static void nsp32_analyze_sdtr(struct scsi_cmnd *SCpnt){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; nsp32_target *target = data->cur_target; nsp32_sync_table *synct; unsigned char get_period = data->msginbuf[3]; unsigned char get_offset = data->msginbuf[4]; int entry; int syncnum; nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter"); synct = data->synct; syncnum = data->syncnum; /* * If this inititor sent the SDTR message, then target responds SDTR, * initiator SYNCREG, ACKWIDTH from SDTR parameter. * Messages are not appropriate, then send back reject message. * If initiator did not send the SDTR, but target sends SDTR, * initiator calculator the appropriate parameter and send back SDTR. */ if (target->sync_flag & SDTR_INITIATOR) { /* * Initiator sent SDTR, the target responds and * send back negotiation SDTR. */ nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR"); target->sync_flag &= ~SDTR_INITIATOR; target->sync_flag |= SDTR_DONE; /* * offset: */ if (get_offset > SYNC_OFFSET) { /* * Negotiation is failed, the target send back * unexpected offset value. */ goto reject; } if (get_offset == ASYNC_OFFSET) { /* * Negotiation is succeeded, the target want * to fall back into asynchronous transfer mode. */ goto async; } /* * period: * Check whether sync period is too short. If too short, * fall back to async mode. If it's ok, then investigate * the received sync period. If sync period is acceptable * between sync table start_period and end_period, then * set this I_T nexus as sent offset and period. * If it's not acceptable, send back reject and fall back * to async mode. */ if (get_period < data->synct[0].period_num) { /* * Negotiation is failed, the target send back * unexpected period value. */ goto reject; } entry = nsp32_search_period_entry(data, target, get_period); if (entry < 0) { /* * Target want to use long period which is not * acceptable NinjaSCSI-32Bi/UDE. */ goto reject; } /* * Set new sync table and offset in this I_T nexus. */ nsp32_set_sync_entry(data, target, entry, get_offset); } else { /* Target send SDTR to initiator. */ nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target send SDTR"); target->sync_flag |= SDTR_INITIATOR; /* offset: */ if (get_offset > SYNC_OFFSET) { /* send back as SYNC_OFFSET */ get_offset = SYNC_OFFSET; } /* period: */ if (get_period < data->synct[0].period_num) { get_period = data->synct[0].period_num; } entry = nsp32_search_period_entry(data, target, get_period); if (get_offset == ASYNC_OFFSET || entry < 0) { nsp32_set_async(data, target); nsp32_build_sdtr(SCpnt, 0, ASYNC_OFFSET); } else { nsp32_set_sync_entry(data, target, entry, get_offset); nsp32_build_sdtr(SCpnt, get_period, get_offset); } } target->period = get_period; nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit"); return; reject: /* * If the current message is unacceptable, send back to the target * with reject message. */ nsp32_build_reject(SCpnt); async: nsp32_set_async(data, target); /* set as ASYNC transfer mode */ target->period = 0; nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit: set async"); return;}/* * Search config entry number matched in sync_table from given * target and speed period value. If failed to search, return negative value. */static int nsp32_search_period_entry(nsp32_hw_data *data, nsp32_target *target, unsigned char period){ int i; if (target->limit_entry >= data->syncnum) { nsp32_msg(KERN_ERR, "limit_entry exceeds syncnum!"); target->limit_entry = 0; } for (i = target->limit_entry; i < data->syncnum; i++) { if (period >
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?