📄 acornscsi.c.2
字号:
DBG(host->SCpnt, printk ("scsi%d.%c: had to move command " "to disconnected queue\n", host->host->host_no, acornscsi_target (host)));#endif host->SCpnt = NULL; } } if (!host->SCpnt) { host->SCpnt = queue_remove_tgtluntag (&host->queues.disconnected, host->scsi.reconnected.target, host->scsi.reconnected.lun, host->scsi.reconnected.tag);#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) DBG(host->SCpnt, printk ("scsi%d.%c: had to get command", host->host->host_no, acornscsi_target (host)));#endif } if (!host->SCpnt) { acornscsi_abortcmd (host, host->scsi.reconnected.tag); host->scsi.phase = PHASE_ABORTED; } else { /* * Restore data pointer from SAVED pointers. */ host->scsi.SCp = host->SCpnt->SCp;#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) printk (", data pointers: [%p, %X]", host->scsi.SCp.ptr, host->scsi.SCp.this_residual);#endif }#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) printk ("\n");#endif host->dma.transferred = host->scsi.SCp.have_data_in; return host->SCpnt != NULL;}/* * Function: void acornscsi_disconnect_unexpected (AS_Host *host) * Purpose : handle an unexpected disconnect * Params : host - host on which disconnect occurred */staticvoid acornscsi_disconnect_unexpected (AS_Host *host){ printk (KERN_ERR "scsi%d.%c: unexpected disconnect\n", host->host->host_no, acornscsi_target (host));#if (DEBUG & DEBUG_ABORT) acornscsi_dumplog (host, 8);#endif acornscsi_done (host, &host->SCpnt, DID_ABORT);}/* * Function: void acornscsi_abortcmd (AS_host *host, unsigned char tag) * Purpose : abort a currently executing command * Params : host - host with connected command to abort * tag - tag to abort */staticvoid acornscsi_abortcmd (AS_Host *host, unsigned char tag){ sbic_arm_write (host->scsi.io_port, CMND, CMND_ASSERTATN); msgqueue_flush (&host->scsi.msgs);#ifdef SCSI2_TAG if (tag) msgqueue_addmsg (&host->scsi.msgs, 2, ABORT_TAG, tag); else#endif msgqueue_addmsg (&host->scsi.msgs, 1, ABORT);}/* ========================================================================================== * Interrupt routines. *//* * Function: int acornscsi_sbicintr (AS_Host *host) * Purpose : handle interrupts from SCSI device * Params : host - host to process * Returns : INTR_PROCESS if expecting another SBIC interrupt * INTR_IDLE if no interrupt * INTR_NEXT_COMMAND if we have finished processing the command */staticintr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq){ unsigned int asr, ssr; asr = sbic_arm_read (host->scsi.io_port, ASR); if (!(asr & ASR_INT)) return INTR_IDLE; ssr = sbic_arm_read (host->scsi.io_port, SSR);#if (DEBUG & DEBUG_PHASES) print_sbic_status(asr, ssr, host->scsi.phase);#endif ADD_STATUS(8, ssr, host->scsi.phase, in_irq); if (host->SCpnt && !host->scsi.disconnectable) ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq); switch (ssr) { case 0x00: /* reset state - not advanced */ printk (KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n", host->host->host_no); /* setup sbic - WD33C93A */ sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); return INTR_IDLE; case 0x01: /* reset state - advanced */ sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); msgqueue_flush (&host->scsi.msgs); return INTR_IDLE; case 0x41: /* unexpected disconnect aborted command */ acornscsi_disconnect_unexpected (host); return INTR_NEXT_COMMAND; } switch (host->scsi.phase) { case PHASE_CONNECTING: /* STATE: command removed from issue queue */ switch (ssr) { case 0x11: /* -> PHASE_CONNECTED */ /* BUS FREE -> SELECTION */ host->scsi.phase = PHASE_CONNECTED; msgqueue_flush (&host->scsi.msgs); host->dma.transferred = host->scsi.SCp.have_data_in; /* 33C93 gives next interrupt indicating bus phase */ asr = sbic_arm_read (host->scsi.io_port, ASR); if (!(asr & ASR_INT)) break; ssr = sbic_arm_read (host->scsi.io_port, SSR); ADD_STATUS(8, ssr, host->scsi.phase, 1); ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, 1); goto connected; case 0x42: /* select timed out */ /* -> PHASE_IDLE */ acornscsi_done (host, &host->SCpnt, DID_NO_CONNECT); return INTR_NEXT_COMMAND; case 0x81: /* -> PHASE_RECONNECTED or PHASE_ABORTED */ /* BUS FREE -> RESELECTION */ host->origSCpnt = host->SCpnt; host->SCpnt = NULL; msgqueue_flush (&host->scsi.msgs); acornscsi_reconnect (host); break; default: printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n", host->host->host_no, acornscsi_target (host), ssr); acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); acornscsi_abortcmd (host, host->SCpnt->tag); } return INTR_PROCESSING; connected: case PHASE_CONNECTED: /* STATE: device selected ok */ switch (ssr) {#ifdef NONSTANDARD case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ /* SELECTION -> COMMAND */ acornscsi_sendcommand (host); break; case 0x8b: /* -> PHASE_STATUS */ /* SELECTION -> STATUS */ acornscsi_readstatusbyte (host); break;#endif case 0x8e: /* -> PHASE_MSGOUT */ /* SELECTION ->MESSAGE OUT */ host->scsi.phase = PHASE_MSGOUT; acornscsi_buildmessages (host); acornscsi_sendmessage (host); break; /* these should not happen */ case 0x85: /* target disconnected */ acornscsi_done (host, &host->SCpnt, DID_ERROR); break; default: printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n", host->host->host_no, acornscsi_target (host), ssr); acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); acornscsi_abortcmd (host, host->SCpnt->tag); } return INTR_PROCESSING; case PHASE_MSGOUT: /* STATE: connected & sent IDENTIFY message */ /* * SCSI standard says th at a MESSAGE OUT phases can be followed by a DATA phase */ switch (ssr) { case 0x8a: case 0x1a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ /* MESSAGE OUT -> COMMAND */ acornscsi_sendcommand (host); break; case 0x1b: /* -> PHASE_STATUS */ /* MESSAGE OUT -> STATUS */ acornscsi_readstatusbyte (host); break; case 0x4f: case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ /* MESSAGE OUT -> MESSAGE IN */ acornscsi_message (host); break; default: printk (KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n", host->host->host_no, acornscsi_target (host), ssr); acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_COMMAND: /* STATE: connected & command sent */ switch (ssr) { case 0x18: /* -> PHASE_DATAOUT */ /* COMMAND -> DATA OUT */ if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) acornscsi_abortcmd (host, host->SCpnt->tag); acornscsi_dma_setup (host, DMA_OUT); if (!acornscsi_starttransfer (host)) acornscsi_abortcmd (host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAOUT; return INTR_IDLE; case 0x19: /* -> PHASE_DATAIN */ /* COMMAND -> DATA IN */ if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) acornscsi_abortcmd (host, host->SCpnt->tag); acornscsi_dma_setup (host, DMA_IN); if (!acornscsi_starttransfer (host)) acornscsi_abortcmd (host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAIN; return INTR_IDLE; case 0x1b: /* -> PHASE_STATUS */ /* COMMAND -> STATUS */ acornscsi_readstatusbyte (host); break; case 0x1e: /* -> PHASE_MSGOUT */ /* COMMAND -> MESSAGE OUT */ acornscsi_sendmessage (host); break; case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ /* COMMAND -> MESSAGE IN */ acornscsi_message (host); break; default: printk (KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n", host->host->host_no, acornscsi_target (host), ssr); acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_DISCONNECT: /* STATE: connected, received DISCONNECT msg */ if (ssr == 0x85) { /* -> PHASE_IDLE */ host->scsi.disconnectable = 1; host->scsi.reconnected.tag = 0; host->scsi.phase = PHASE_IDLE; host->stats.disconnects += 1; } else { printk (KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n", host->host->host_no, acornscsi_target (host), ssr); acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_NEXT_COMMAND; case PHASE_IDLE: /* STATE: disconnected */ if (ssr == 0x81) /* -> PHASE_RECONNECTED or PHASE_ABORTED */ acornscsi_reconnect (host); else { printk (KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n", host->host->host_no, acornscsi_target (host), ssr); acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_RECONNECTED: /* STATE: device reconnected to initiator */ /* * Command reconnected - if MESGIN, get message - it may be * the tag. If not, get command out of disconnected queue */ /* * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY, * reconnect I_T_L command */ if (ssr != 0x8f && !acornscsi_reconnect_finish (host)) return INTR_IDLE; ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq); switch (ssr) { case 0x88: /* data out phase */ /* -> PHASE_DATAOUT */ /* MESSAGE IN -> DATA OUT */ acornscsi_dma_setup (host, DMA_OUT); if (!acornscsi_starttransfer (host)) acornscsi_abortcmd (host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAOUT; return INTR_IDLE; case 0x89: /* data in phase */ /* -> PHASE_DATAIN */ /* MESSAGE IN -> DATA IN */ acornscsi_dma_setup (host, DMA_IN); if (!acornscsi_starttransfer (host)) acornscsi_abortcmd (host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAIN; return INTR_IDLE; case 0x8a: /* command out */ /* MESSAGE IN -> COMMAND */ acornscsi_sendcommand (host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ break; case 0x8b: /* status in */ /* -> PHASE_STATUSIN */ /* MESSAGE IN -> STATUS */ acornscsi_readstatusbyte (host); break; case 0x8e: /* message out */ /* -> PHASE_MSGOUT */ /* MESSAGE IN -> MESSAGE OUT */ acornscsi_sendmessage (host); break; case 0x8f: /* message in */ acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ break; default: printk (KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n", host->host->host_no, acornscsi_target (host), ssr); acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_DATAIN: /* STATE: transferred data in */ /* * This is simple - if we disconnect then the DMA address & count is * correct. */ switch (ssr) { case 0x19: /* -> PHASE_DATAIN */ acornscsi_abortcmd (host, host->SCpnt->tag); return INTR_IDLE; case 0x4b: /* -> PHASE_STATUSIN */ case 0x1b: /* -> PHASE_STATUSIN */ /* DATA IN -> STATUS */ host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount (host); acornscsi_dma_stop (host); acornscsi_readstatusbyte (host); break; case 0x1e: /* -> PHASE_MSGOUT */ case 0x4e: /* -> PHASE_MSGOUT */ /* DATA IN -> MESSAGE OUT */ host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount (host); acornscsi_dma_stop (host); acornscsi_sendmessage (host); break; case 0x1f: /* message in */ case 0x4f: /* message in */ /* DATA IN -> MESSAGE IN */ host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount (host); acornscsi_dma_stop (host); acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ break; default: printk (KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n", host->host->host_no, acornscsi_target (host), ssr); acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_DATAOUT: /* STATE: transferred data out */ /* * This is more complicated - if we disconnect, the DMA could be 12 * bytes ahead of us. We need to correct this. */ switch (ssr) { case 0x18: /* -> PHASE_DATAOUT */ acornscsi_abortcmd (host, host->SCpnt->tag); return INTR_IDLE; case 0x4b: /* -> PHASE_STATUSIN */ case 0x1b: /* -> PHASE_STATUSIN */ /* DATA OUT -> STATUS */ host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount (host); acornscsi_dma_stop (host); acornscsi_dma_adjust (host); acornscsi_readstatusbyte (host); break; case 0x1e: /* -> PHASE_MSGOUT */ case 0x4e: /* -> PHASE_MSGOUT */ /* DATA OUT -> MESSAGE OUT */ host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount (host); acornscsi_dma_stop (host); acornscsi_dma_adjust (host); acornscsi_sendmessage (host); break; case 0x1f: /* message in */ case 0x4f: /* message in */ /* DATA OUT -> MESSAGE IN */ host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount (host); acornscsi_dma_stop (host); acornscsi_dma_adjust (host
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -