/* transfer control */
s = 0; switch (data->trans_method) { case NSP32_TRANSFER_BUSMASTER:
s |= BM_START; break; case NSP32_TRANSFER_MMIO:
s |= CB_MMIO_MODE; break; case NSP32_TRANSFER_PIO:
s |= CB_IO_MODE; break; default:
nsp32_msg(KERN_ERR, "unknown trans_method"); break;
} /* * OR-ed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits. * For bus master transfer, it's taken off.
*/
s |= (TRANSFER_GO | ALL_COUNTER_CLR);
param->transfer_control = cpu_to_le16(s);
/* * Arbitration Status Check * * Note: Arbitration counter is waited during ARBIT_GO is not lifting. * Using udelay(1) consumes CPU time and system time, but * arbitration delay time is defined minimal 2.4us in SCSI * specification, thus udelay works as coarse grained wait timer.
*/ staticint nsp32_arbitration(struct scsi_cmnd *SCpnt, unsignedint base)
{ unsignedchar arbit; int status = TRUE; int time = 0;
do {
arbit = nsp32_read1(base, ARBIT_STATUS);
time++;
} while ((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
(time <= ARBIT_TIMEOUT_TIME));
/* * reselection * * Note: This reselection routine is called from msgin_occur, * reselection target id&lun must be already set. * SCSI-2 says IDENTIFY implies RESTORE_POINTER operation.
*/ staticint nsp32_reselection(struct scsi_cmnd *SCpnt, unsignedchar newlun)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsignedint host_id = SCpnt->device->host->this_id; unsignedint base = SCpnt->device->host->io_port; unsignedchar tmpid, newid;
nsp32_dbg(NSP32_DEBUG_RESELECTION, "enter");
/* * calculate reselected SCSI ID
*/
tmpid = nsp32_read1(base, RESELECT_ID);
tmpid &= (~BIT(host_id));
newid = 0; while (tmpid) { if (tmpid & 1) { break;
}
tmpid >>= 1;
newid++;
}
/* * If reselected New ID:LUN is not existed * or current nexus is not existed, unexpected * reselection is occurred. Send reject message.
*/ if (newid >= ARRAY_SIZE(data->lunt) ||
newlun >= ARRAY_SIZE(data->lunt[0])) {
nsp32_msg(KERN_WARNING, "unknown id/lun"); returnFALSE;
} elseif(data->lunt[newid][newlun].SCpnt == NULL) {
nsp32_msg(KERN_WARNING, "no SCSI command is processing"); returnFALSE;
}
/* * nsp32_setup_sg_table - build scatter gather list for transfer data * with bus master. * * Note: NinjaSCSI-32Bi/UDE bus master can not transfer over 64KB at a time.
*/ staticint nsp32_setup_sg_table(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; struct scatterlist *sg;
nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt; int num, i;
u32_le l;
if (le32_to_cpu(sgt[i].len) > 0x10000) {
nsp32_msg(KERN_ERR, "can't transfer over 64KB at a time, " "size=0x%x", le32_to_cpu(sgt[i].len)); returnFALSE;
}
nsp32_dbg(NSP32_DEBUG_SGLIST, "num 0x%x : addr 0x%lx len 0x%lx",
i,
le32_to_cpu(sgt[i].addr),
le32_to_cpu(sgt[i].len ));
}
/* set end mark */
l = le32_to_cpu(sgt[num-1].len);
sgt[num-1].len = cpu_to_le32(l | SGTEND);
}
/* check target ID is not same as this initiator ID */ if (scmd_id(SCpnt) == SCpnt->device->host->this_id) {
nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "target==host???");
SCpnt->result = DID_BAD_TARGET << 16;
done(SCpnt); return 0;
}
/* check target LUN is allowable value */ if (SCpnt->device->lun >= MAX_LUN) {
nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "no more lun");
SCpnt->result = DID_BAD_TARGET << 16;
done(SCpnt); return 0;
}
ret = nsp32_setup_sg_table(SCpnt); if (ret == FALSE) {
nsp32_msg(KERN_ERR, "SGT fail");
SCpnt->result = DID_ERROR << 16;
nsp32_scsi_done(SCpnt); return 0;
}
/* Build IDENTIFY */
nsp32_build_identify(SCpnt);
/* * If target is the first time to transfer after the reset * (target don't have SDTR_DONE and SDTR_INITIATOR), sync * message SDTR is needed to do synchronous transfer.
*/
target = &data->target[scmd_id(SCpnt)];
data->cur_target = target;
nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "SDTR: entry: %d start_period: 0x%x offset: 0x%x\n",
target->limit_entry, period, offset);
} elseif (target->sync_flag & SDTR_INITIATOR) { /* * It was negotiating SDTR with target, sending from the * initiator, but there are no chance to remove this flag. * Set async because we don't get proper negotiation.
*/
nsp32_set_async(data, target);
target->sync_flag &= ~SDTR_INITIATOR;
target->sync_flag |= SDTR_DONE;
nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "SDTR_INITIATOR: fall back to async");
} elseif (target->sync_flag & SDTR_TARGET) { /* * It was negotiating SDTR with target, sending from target, * but there are no chance to remove this flag. Set async * because we don't get proper negotiation.
*/
nsp32_set_async(data, target);
target->sync_flag &= ~SDTR_TARGET;
target->sync_flag |= SDTR_DONE;
nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "Unknown SDTR from target is reached, fall back to async.");
}
/* * initialize MISC_WRRD register * * Note: Designated parameters is obeyed as following: * MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set. * MISC_MASTER_TERMINATION_SELECT: It must be set. * MISC_BMREQ_NEGATE_TIMING_SEL: It should be set. * MISC_AUTOSEL_TIMING_SEL: It should be set. * MISC_BMSTOP_CHANGE2_NONDATA_PHASE: It should be set. * MISC_DELAYED_BMSTART: It's selected for safety. * * Note: If MISC_BMSTOP_CHANGE2_NONDATA_PHASE is set, then * we have to set TRANSFERCONTROL_BM_START as 0 and set * appropriate value before restarting bus master transfer.
*/
nsp32_index_write2(base, MISC_WR,
(SCSI_DIRECTION_DETECTOR_SELECT |
DELAYED_BMSTART |
MASTER_TERMINATION_SELECT |
BMREQ_NEGATE_TIMING_SEL |
AUTOSEL_TIMING_SEL |
BMSTOP_CHANGE2_NONDATA_PHASE));
nsp32_index_write1(base, TERM_PWR_CONTROL, 0);
power = nsp32_index_read1(base, TERM_PWR_CONTROL); if (!(power & SENSE)) {
nsp32_msg(KERN_INFO, "term power on");
nsp32_index_write1(base, TERM_PWR_CONTROL, BPWR);
}
/* SCSI reset */ if (irq_stat & IRQSTATUS_SCSIRESET_IRQ) {
nsp32_msg(KERN_INFO, "detected someone do bus reset");
nsp32_do_bus_reset(data); if (SCpnt != NULL) {
SCpnt->result = DID_RESET << 16;
nsp32_scsi_done(SCpnt);
} goto out;
}
if (SCpnt == NULL) {
nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happened");
nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x",
irq_stat, trans_stat); goto out;
}
/* * AutoSCSI Interrupt. * Note: This interrupt is occurred when AutoSCSI is finished. Then * check SCSIEXECUTEPHASE, and do appropriate action. Each phases are * recorded when AutoSCSI sequencer has been processed.
*/ if(irq_stat & IRQSTATUS_AUTOSCSI_IRQ) { /* getting SCSI executed phase */
auto_stat = nsp32_read2(base, SCSI_EXECUTE_PHASE);
nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
/* Selection Timeout, go busfree phase. */ if (auto_stat & SELECTION_TIMEOUT) {
nsp32_dbg(NSP32_DEBUG_INTR, "selection timeout occurred");
if (auto_stat & MSGOUT_PHASE) { /* * MsgOut phase was processed. * If MSG_IN_OCCUER is not set, then MsgOut phase is * completed. Thus, msgout_len must reset. Otherwise, * nothing to do here. If MSG_OUT_OCCUER is occurred, * then we will encounter the condition and check.
*/ if (!(auto_stat & MSG_IN_OCCUER) &&
(data->msgout_len <= 3)) { /* * !MSG_IN_OCCUER && msgout_len <=3 * ---> AutoSCSI with MSGOUTreg is processed.
*/
data->msgout_len = 0;
}
/* PCI_IRQ */ if (irq_stat & IRQSTATUS_PCI_IRQ) {
nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occurred"); /* Do nothing */
}
/* BMCNTERR_IRQ */ if (irq_stat & IRQSTATUS_BMCNTERR_IRQ) {
nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! "); /* * TODO: To be implemented improving bus master * transfer reliability when BMCNTERR is occurred in * AutoSCSI phase described in specification.
*/
}
/* * 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))) { unsignedint 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 transferring.
*/ 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;
} elseif (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");
/* * 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 transferring */
restlen = sentlen - s_sacklen;
/* 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.
*/ staticvoid nsp32_msgout_occur(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsignedint base = SCpnt->device->host->io_port; int i;
/* * 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);
}
/* * 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);
/* * cannot run automatically message in occur
*/ staticvoid nsp32_msgin_occur(struct scsi_cmnd *SCpnt, unsignedlong irq_status, unsignedshort execph)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsignedint base = SCpnt->device->host->io_port; unsignedchar msg; unsignedchar msgtype; unsignedchar newlun; unsignedshort 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[(unsignedchar)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?
*/
/* * 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.
*/
/* * 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++;
}
/* * 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");
/* * 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;
}
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.
*/ staticint nsp32_search_period_entry(nsp32_hw_data *data,
nsp32_target *target, unsignedchar period)
{ int i;
/* * It waits until SCSI REQ becomes assertion or negation state. * * Note: If nsp32_msgin_occur is called, we asserts SCSI ACK. Then * connected target responds SCSI REQ negation. We have to wait * SCSI REQ becomes negation in order to negate SCSI ACK signal for * REQ-ACK handshake.
*/ staticvoid nsp32_wait_req(nsp32_hw_data *data, int state)
{ unsignedint base = data->BaseAddress; int wait_time = 0; unsignedchar bus, req_bit;
if (!((state == ASSERT) || (state == NEGATE))) {
nsp32_msg(KERN_ERR, "unknown state designation");
} /* REQ is BIT(5) */
req_bit = (state == ASSERT ? BUSMON_REQ : 0);
do {
bus = nsp32_read1(base, SCSI_BUS_MONITOR); if ((bus & BUSMON_REQ) == req_bit) {
nsp32_dbg(NSP32_DEBUG_WAIT, "wait_time: %d", wait_time); return;
}
udelay(1);
wait_time++;
} while (wait_time < REQSACK_TIMEOUT_TIME);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.