📄 acornscsi.c.dag2
字号:
*/staticunsigned char acornscsi_readmessagebyte (AS_Host *host){ unsigned char message; acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); message = sbic_arm_read (host->scsi.io_port, DATA); /* wait for MSGIN-XFER-PAUSED */ while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); sbic_arm_read (host->scsi.io_port, SSR); return message;}/* * Function: void acornscsi_message (AS_Host *host) * Purpose : Read complete message from connected target & action message * Params : host - host connected to target */staticvoid acornscsi_message (AS_Host *host){ unsigned char message[16]; unsigned int msgidx = 0, msglen = 1; do { message[msgidx] = acornscsi_readmessagebyte (host); switch (msgidx) { case 0: if (message[0] == EXTENDED_MESSAGE || (message[0] >= 0x20 && message[0] <= 0x2f)) msglen = 2; break; case 1: if (message[0] == EXTENDED_MESSAGE) msglen += message[msgidx]; break; } msgidx += 1; if (msgidx < msglen) { acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); /* wait for next msg-in */ while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); sbic_arm_read (host->scsi.io_port, SSR); } } while (msgidx < msglen);#if (DEBUG & DEBUG_MESSAGES) printk (KERN_DEBUG "scsi%d.%c: message in: ", host->host->host_no, acornscsi_target (host)); print_msg (message); printk ("\n");#endif if (host->scsi.phase == PHASE_RECONNECTED) { /* * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17) * 'Whenever a target reconnects to an initiator to continue * a tagged I/O process, the SIMPLE QUEUE TAG message shall * be sent immediately following the IDENTIFY message...' */ if (message[0] == SIMPLE_QUEUE_TAG) host->scsi.reconnected.tag = message[1]; if (acornscsi_reconnect_finish (host)) host->scsi.phase = PHASE_MSGIN; } switch (message[0]) { case ABORT: case ABORT_TAG: case COMMAND_COMPLETE: if (host->scsi.phase != PHASE_STATUSIN) printk (KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n", host->host->host_no, acornscsi_target (host)); host->scsi.phase = PHASE_DONE; host->scsi.SCp.Message = message[0]; break; case SAVE_POINTERS: /* * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.20) * 'The SAVE DATA POINTER message is sent from a target to * direct the initiator to copy the active data pointer to * the saved data pointer for the current I/O process. */ acornscsi_dma_cleanup (host); host->SCpnt->SCp = host->scsi.SCp; host->SCpnt->SCp.sent_command = 0; host->scsi.phase = PHASE_MSGIN; break; case RESTORE_POINTERS: /* * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.19) * 'The RESTORE POINTERS message is sent from a target to * direct the initiator to copy the most recently saved * command, data, and status pointers for the I/O process * to the corresponding active pointers. The command and * status pointers shall be restored to the beginning of * the present command and status areas.' */ acornscsi_dma_cleanup (host); host->scsi.SCp = host->SCpnt->SCp; host->scsi.phase = PHASE_MSGIN; break; case DISCONNECT: /* * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 6.4.2) * 'On those occasions when an error or exception condition occurs * and the target elects to repeat the information transfer, the * target may repeat the transfer either issuing a RESTORE POINTERS * message or by disconnecting without issuing a SAVE POINTERS * message. When reconnection is completed, the most recent * saved pointer values are restored.' */ acornscsi_dma_cleanup (host); host->scsi.phase = PHASE_DISCONNECT; break; case MESSAGE_REJECT:#if 0 /* this isn't needed any more */ /* * If we were negociating sync transfer, we don't yet know if * this REJECT is for the sync transfer or for the tagged queue/wide * transfer. Re-initiate sync transfer negociation now, and if * we got a REJECT in response to SDTR, then it'll be set to DONE. */ if (host->device[host->SCpnt->target].sync_state == SYNC_SENT_REQUEST) host->device[host->SCpnt->target].sync_state = SYNC_NEGOCIATE;#endif /* * If we have any messages waiting to go out, then assert ATN now */ if (msgqueue_msglength (&host->scsi.msgs)) acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); switch (host->scsi.last_message) {#ifdef SCSI2_TAG case HEAD_OF_QUEUE_TAG: case ORDERED_QUEUE_TAG: case SIMPLE_QUEUE_TAG: /* * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17) * If a target does not implement tagged queuing and a queue tag * message is received, it shall respond with a MESSAGE REJECT * message and accept the I/O process as if it were untagged. */ printk (KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", host->host->host_no, acornscsi_target (host)); host->SCpnt->device->tagged_queue = 0; set_bit (host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns); break;#endif case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8): /* * Target can't handle synchronous transfers */ printk (KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n", host->host->host_no, acornscsi_target (host)); host->device[host->SCpnt->target].sync_xfer = SYNCHTRANSFER_2DBA; host->device[host->SCpnt->target].sync_state = SYNC_ASYNCHRONOUS; sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); break; default: break; } break; case QUEUE_FULL: /* TODO: target queue is full */ break; case SIMPLE_QUEUE_TAG: /* tag queue reconnect... message[1] = queue tag. Print something to indicate something happened! */ printk ("scsi%d.%c: reconnect queue tag %02X\n", host->host->host_no, acornscsi_target (host), message[1]); break; case EXTENDED_MESSAGE: switch (message[2]) {#ifdef SCSI2_SYNC case EXTENDED_SDTR: if (host->device[host->SCpnt->target].sync_state == SYNC_SENT_REQUEST) { /* * We requested synchronous transfers. This isn't quite right... * We can only say if this succeeded if we proceed on to execute the * command from this message. If we get a MESSAGE PARITY ERROR, * and the target retries fail, then we fallback to asynchronous mode */ host->device[host->SCpnt->target].sync_state = SYNC_COMPLETED; printk (KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n", host->host->host_no, acornscsi_target(host), message[4], message[3] * 4); host->device[host->SCpnt->target].sync_xfer = calc_sync_xfer (message[3] * 4, message[4]); } else { unsigned char period, length; /* * Target requested synchronous transfers. The agreement is only * to be in operation AFTER the target leaves message out phase. */ acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); period = max (message[3], sdtr_period / 4); length = min (message[4], sdtr_size); msgqueue_addmsg (&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, period, length); host->device[host->SCpnt->target].sync_xfer = calc_sync_xfer (period * 4, length); } sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); break;#else /* We do not accept synchronous transfers. Respond with a * MESSAGE_REJECT. */#endif case EXTENDED_WDTR: /* The WD33C93A is only 8-bit. We respond with a MESSAGE_REJECT * to a wide data transfer request. */ default: acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); msgqueue_flush (&host->scsi.msgs); msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); break; } break;#ifdef SCSI2_LINK case LINKED_CMD_COMPLETE: case LINKED_FLG_CMD_COMPLETE: /* * We don't support linked commands yet */ if (0) {#if (DEBUG & DEBUG_LINK) printk (KERN_DEBUG "scsi%d.%c: lun %d tag %d linked command complete\n", host->host->host_no, acornscsi_target(host), host->SCpnt->tag);#endif /* * A linked command should only terminate with one of these messages * if there are more linked commands available. */ if (!host->SCpnt->next_link) { printk (KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n", instance->host_no, acornscsi_target (host), host->SCpnt->tag); acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); } else { Scsi_Cmnd *SCpnt = host->SCpnt; acornscsi_dma_cleanup (host); host->SCpnt = host->SCpnt->next_link; host->SCpnt->tag = SCpnt->tag; SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status; SCpnt->done (SCpnt); /* initialise host->SCpnt->SCp */ } break; }#endif default: /* reject message */ printk (KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n", host->host->host_no, acornscsi_target (host), message[0]); acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); msgqueue_flush (&host->scsi.msgs); msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); host->scsi.phase = PHASE_MSGIN; break; } acornscsi_sbic_issuecmd (host, CMND_NEGATEACK);}/* * Function: int acornscsi_buildmessages (AS_Host *host) * Purpose : build the connection messages for a host * Params : host - host to add messages to */staticvoid acornscsi_buildmessages (AS_Host *host){#if 0 /* does the device need resetting? */ if (cmd_reset) { msgqueue_addmsg (&host->scsi.msgs, 1, BUS_DEVICE_RESET); return; }#endif msgqueue_addmsg (&host->scsi.msgs, 1, IDENTIFY(host->device[host->SCpnt->target].disconnect_ok, host->SCpnt->lun));#if 0 /* does the device need the current command aborted */ if (cmd_aborted) { acornscsi_abortcmd (host->SCpnt->tag); return; }#endif#ifdef SCSI2_TAG if (host->SCpnt->tag) { unsigned int tag_type; if (host->SCpnt->cmnd[0] == REQUEST_SENSE || host->SCpnt->cmnd[0] == TEST_UNIT_READY || host->SCpnt->cmnd[0] == INQUIRY) tag_type = HEAD_OF_QUEUE_TAG; else tag_type = SIMPLE_QUEUE_TAG; msgqueue_addmsg (&host->scsi.msgs, 2, tag_type, host->SCpnt->tag); }#endif#ifdef SCSI2_SYNC if (host->device[host->SCpnt->target].sync_state == SYNC_NEGOCIATE) { host->device[host->SCpnt->target].sync_state = SYNC_SENT_REQUEST; msgqueue_addmsg (&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, sdtr_period / 4, sdtr_size); }#endif}/* * Function: int acornscsi_starttransfer (AS_Host *host) * Purpose : transfer data to/from connected target * Params : host - host to which target is connected * Returns : 0 if failure */staticint acornscsi_starttransfer (AS_Host *host){ int residual; if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) { printk (KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n", host->host->host_no, acornscsi_target (host)); return 0; } residual = host->SCpnt->request_bufflen - host->scsi.SCp.have_data_in; sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); sbic_arm_writenext (host->scsi.io_port, residual >> 16); sbic_arm_writenext (host->scsi.io_port, residual >> 8); sbic_arm_writenext (host->scsi.io_port, residual); acornscsi_sbic_issuecmd (host, CMND_XFERINFO); return 1;}/* ========================================================================================= * Connection & Disconnection *//* * Function : acornscsi_reconnect (AS_Host *host) * Purpose : reconnect a previously disconnected command * Params : host - host specific data * Remarks : SCSI spec says: * 'The set of active pointers is restored from the set * of saved pointers upon reconnection of the I/O process' */staticint acornscsi_reconnect (AS_Host *host){ unsigned int target, lun, ok = 0; target = sbic_arm_read (host->scsi.io_port, SOURCEID); if (!(target & 8)) printk (KERN_ERR "scsi%d: invalid source id after reselection " "- device fault?\n", host->host->host_no); target &= 7; if (host->SCpnt && !host->scsi.disconnectable) { printk (KERN_ERR "scsi%d.%d: reconnected while command in " "progress to target %d?\n", host->host->host_no, target, host->SCpnt->target); host->SCpnt = NULL; } lun = sbic_arm_read (host->scsi.io_port, DATA) & 7; host->scsi.reconnected.target = target; host->scsi.reconnected.lun = lun; host->scsi.reconnected.tag = 0; if (host->scsi.disconnectable && host->SCpnt && host->SCpnt->target == target && host->SCpnt->lun == lun) ok = 1; if (!ok && queue_probetgtlun (&host->queues.disconnected, target, lun)) ok = 1; ADD_STATUS(target, 0x81, host->scsi.phase, 0); if (ok) { host->scsi.phase = PHASE_RECONNECTED; } else { /* this doesn't seem to work */ printk (KERN_ERR "scsi%d.%c: reselected with no command " "to reconnect with\n", host->host->host_no, '0' + target); acornscsi_dumplog (host, target); acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); host->scsi.phase = PHASE_ABORTED; } acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); return !ok;}/* * Function: int acornscsi_reconect_finish (AS_Host *host) * Purpose : finish reconnecting a command * Params : host - host to complete * Returns : 0 if failed */staticint acornscsi_reconnect_finish (AS_Host *host){ if (host->scsi.disconnectable && host->SCpnt) { host->scsi.disconnectable = 0; if (host->SCpnt->target == host->scsi.reconnected.target && host->SCpnt->lun == host->scsi.reconnected.lun &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -