📄 acornscsi.c
字号:
#if (DEBUG & DEBUG_MESSAGES) printk("scsi%d.%c: sending message ", host->host->host_no, acornscsi_target(host));#endif switch (message_length) { case 0: acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1"); sbic_arm_write(host->scsi.io_port, SBIC_DATA, NOP); host->scsi.last_message = NOP;#if (DEBUG & DEBUG_MESSAGES) printk("NOP");#endif break; case 1: acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); msg = msgqueue_getmsg(&host->scsi.msgs, 0); acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2"); sbic_arm_write(host->scsi.io_port, SBIC_DATA, msg->msg[0]); host->scsi.last_message = msg->msg[0];#if (DEBUG & DEBUG_MESSAGES) print_msg(msg->msg);#endif break; default: /* * ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.14) * 'When a target sends this (MESSAGE_REJECT) message, it * shall change to MESSAGE IN phase and send this message * prior to requesting additional message bytes from the * initiator. This provides an interlock so that the * initiator can determine which message byte is rejected. */ sbic_arm_write(host->scsi.io_port, SBIC_TRANSCNTH, 0); sbic_arm_writenext(host->scsi.io_port, 0); sbic_arm_writenext(host->scsi.io_port, message_length); acornscsi_sbic_issuecmd(host, CMND_XFERINFO); msgnr = 0; while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) { unsigned int i;#if (DEBUG & DEBUG_MESSAGES) print_msg(msg);#endif i = 0; if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000)) printk("scsi%d: timeout while sending message\n", host->host->host_no); host->scsi.last_message = msg->msg[0]; if (msg->msg[0] == EXTENDED_MESSAGE) host->scsi.last_message |= msg->msg[2] << 8; if (i != msg->length) break; } break; }#if (DEBUG & DEBUG_MESSAGES) printk("\n");#endif}/* * Function: void acornscsi_readstatusbyte(AS_Host *host) * Purpose : Read status byte from connected target * Params : host - host connected to target */staticvoid acornscsi_readstatusbyte(AS_Host *host){ acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT); acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte"); host->scsi.SCp.Status = sbic_arm_read(host->scsi.io_port, SBIC_DATA);}/* * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host) * Purpose : Read one message byte from connected target * Params : host - host connected to target */staticunsigned char acornscsi_readmessagebyte(AS_Host *host){ unsigned char message; acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte"); message = sbic_arm_read(host->scsi.io_port, SBIC_DATA); /* wait for MSGIN-XFER-PAUSED */ acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte"); sbic_arm_read(host->scsi.io_port, SBIC_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 */ acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack"); sbic_arm_read(host->scsi.io_port, SBIC_SSR); } } while (msgidx < msglen);#if (DEBUG & DEBUG_MESSAGES) printk("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)); acornscsi_dumplog(host, host->SCpnt->device->id); } 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->device->id].sync_state == SYNC_SENT_REQUEST) host->device[host->SCpnt->device->id].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 CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE 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->simple_tags = 0; set_bit(host->SCpnt->device->id * 8 + host->SCpnt->device->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->device->id].sync_xfer = SYNCHTRANSFER_2DBA; host->device[host->SCpnt->device->id].sync_state = SYNC_ASYNCHRONOUS; sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].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 CONFIG_SCSI_ACORNSCSI_SYNC case EXTENDED_SDTR: if (host->device[host->SCpnt->device->id].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->device->id].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->device->id].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_t(unsigned int, message[3], sdtr_period / 4); length = min_t(unsigned int, message[4], sdtr_size); msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, period, length); host->device[host->SCpnt->device->id].sync_xfer = calc_sync_xfer(period * 4, length); } sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].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 CONFIG_SCSI_ACORNSCSI_LINK case LINKED_CMD_COMPLETE: case LINKED_FLG_CMD_COMPLETE: /* * We don't support linked commands yet */ if (0) {#if (DEBUG & DEBUG_LINK) printk("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->device->id].disconnect_ok, host->SCpnt->device->lun));#if 0 /* does the device need the current command aborted */ if (cmd_aborted) { acornscsi_abortcmd(host->SCpnt->tag); return; }#endif#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE 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 CONFIG_SCSI_ACORNSCSI_SYNC if (host->device[host->SCpnt->device->id].sync_state == SYNC_NEGOCIATE) { host->device[host->SCpnt->device->id].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",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -