nsp32.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,409 行 · 第 1/5 页
C
2,409 行
} /* * 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(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); /* * set TRANSFER CONTROL REG */ transfer = 0; transfer |= (TRANSFER_GO | ALL_COUNTER_CLR); if (data->trans_method & NSP32_TRANSFER_BUSMASTER) { if (SCpnt->request_bufflen > 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(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(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 r
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?