📄 ncr5380.c
字号:
#if 1 while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH));#else if (NCR5380_read(STATUS_REG) & SR_REQ) { for (; timeout && !(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); --timeout); for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ); --timeout); } #endif #if (NDEBUG & NDEBUG_LAST_BYTE_SENT) if (!timeout) printk("scsi%d : timed out on last byte\n", instance->host_no);#endif if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT;#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) printk("scsi%d : last bit sent works\n", instance->host_no);#endif } } } else while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT));#else udelay (5);#endif } } NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_write(MODE_REG, MR_BASE); *data = d + c; *count = 0; *phase = (NCR5380_read(STATUS_REG & PHASE_MASK));#if defined(PSEUDO_DMA) && !defined(UNSAFE) sti();#endif /* defined(REAL_DMA_POLL) */ return foo;#endif /* def REAL_DMA */}#endif /* defined(REAL_DMA) | defined(PSEUDO_DMA) *//* * Function : NCR5380_information_transfer (struct Scsi_Host *instance) * * Purpose : run through the various SCSI phases and do as the target * directs us to. Operates on the currently connected command, * instance->connected. * * Inputs : instance, instance for which we are doing commands * * Side effects : SCSI things happen, the disconnected queue will be * modified if a command disconnects, *instance->connected will * change. * * XXX Note : we need to watch for bus free or a reset condition here * to recover from an unexpected bus free condition. */ static void NCR5380_information_transfer (struct Scsi_Host *instance) { NCR5380_local_declare(); struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; unsigned char msgout = NOP; int len, transfersize; unsigned char *data; unsigned char phase, tmp, old_phase=0xff; Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; NCR5380_setup(instance); while (1) { tmp = NCR5380_read(STATUS_REG); /* We only have a valid SCSI phase when REQ is asserted */ if (tmp & SR_REQ) { phase = (tmp & PHASE_MASK); if (phase != old_phase) { old_phase = phase;#if (NDEBUG & NDEBUG_INFORMATION) NCR5380_print_phase(instance);#endif } switch (phase) { case PHASE_DATAIN: case PHASE_DATAOUT:#if (NDEBUG & NDEBUG_NO_DATAOUT) printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", instance->host_no); msgout = ABORT; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); break;#endif /* * If there is no room left in the current buffer in the * scatter-gather list, move onto the next one. */ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { ++cmd->SCp.buffer; --cmd->SCp.buffers_residual; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = cmd->SCp.buffer->address;#if (NDEBUG & NDEBUG_INFORMATION) printk("scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual);#endif } /* * The preffered transfer method is going to be * PSEUDO-DMA for systems that are strictly PIO, * since we can let the hardware do the handshaking. * * For this to work, we need to know the transfersize * ahead of time, since the pseudo-DMA code will sit * in an unconditional loop. */#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)#ifdef NCR5380_dma_xfer_len if (!scsi_devices[cmd->index].borken && (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {#else if (!scsi_devices[cmd->index].borken && (transfersize = cmd->transfersize) && cmd->SCp.this_residual && !(cmd->SCp.this_residual % transfersize)) {#endif len = transfersize; if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) { /* * If the watchdog timer fires, all future accesses to this * device will use the polled-IO. */ printk("scsi%d : switching target %d lun %d to slow handshake\n", instance->host_no, cmd->target, cmd->lun); scsi_devices[cmd->index].borken = 1; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); msgout = ABORT; } else cmd->SCp.this_residual -= transfersize - len; } else#endif /* defined(REAL_DMA) || defined(REAL_DMA_POLL) */ NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **) &cmd->SCp.ptr); break; case PHASE_MSGIN: /* * XXX - we don't handle multi-byte messages here, since we * shouldn't get them after the I_T_L_Q nexus is established * for tagged queuing, and the host should initiate any * negotiations for sync. SCSI, etc. */ len = 1; data = &tmp; NCR5380_transfer_pio(instance, &phase, &len, &data); cmd->SCp.Message = tmp; switch (tmp) { /* * Linking lets us reduce the time required to get the * next command out to the device, hopefully this will * mean we don't waste another revolution due to the delays * required by ARBITRATION and another SELECTION. * * In the current implementation proposal, low level drivers * merely have to start the next command, pointed to by * next_link, done() is called as with unlinked commands. */#ifdef LINKED case LINKED_CMD_COMPLETE: case LINKED_FLG_CMD_COMPLETE:#if (NDEBUG & NDEBUG_LINKED) printk("scsi%d : target %d lun %d linked command complete.\n", instance->host_no, cmd->target, cmd->lun);#endif /* * Sanity check : A linked command should only terminate with * one of these messages if there are more linked commands * available. */ if (!cmd->next_link) { printk("scsi%d : target %d lun %d linked command complete, no next_link\n" instance->host_no, cmd->target, cmd->lun); msgout = ABORT; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); break; } initialize_SCp(cmd->next_link); /* The next command is still part of this process */ cmd->next_link->tag = cmd->tag; cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); #if (NDEBUG & NDEBUG_LINKED) printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", instance->host_no, cmd->target, cmd->lun);#endif cmd->scsi_done(cmd); cmd = hostdata->connected; break;#endif /* def LINKED */ case ABORT: case COMMAND_COMPLETE: hostdata->connected = NULL;#if (NDEBUG & NDEBUG_QUEUES) printk("scsi%d : command for target %d, lun %d completed\n", instance->host_no, cmd->target, cmd->lun);#endif hostdata->busy[cmd->target] &= ~(1 << cmd->lun); /* * I'm not sure what the correct thing to do here is : * * If the command that just executed is NOT a request * sense, the obvious thing to do is to set the result * code to the values of the stored parameters. * * If it was a REQUEST SENSE command, we need some way * to differentiate between the failure code of the original * and the failure code of the REQUEST sense - the obvious * case is success, where we fall through and leave the result * code unchanged. * * The non-obvious place is where the REQUEST SENSE failed */ if (cmd->cmnd[0] != REQUEST_SENSE) cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); else if (cmd->SCp.Status != GOOD) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); #ifdef AUTOSENSE if ((cmd->cmnd[0] != REQUEST_SENSE) && (cmd->SCp.Status == CHECK_CONDITION)) {#if (NDEBUG & NDEBUG_AUTOSENSE) printk("scsi%d : performing request sense\n", instance->host_no);#endif cmd->cmnd[0] = REQUEST_SENSE; cmd->cmnd[1] &= 0xe0; cmd->cmnd[2] = 0; cmd->cmnd[3] = 0; cmd->cmnd[4] = sizeof(cmd->sense_buffer); cmd->cmnd[5] = 0; cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; cmd->SCp.ptr = (char *) cmd->sense_buffer; cmd->SCp.this_residual = sizeof(cmd->sense_buffer); cli(); cmd->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = (Scsi_Cmnd *) cmd; sti();#if (NDEBUG & NDEBUG_QUEUES) printk("scsi%d : REQUEST SENSE added to head of issue queue\n");#endif } else#endif /* def AUTOSENSE */ cmd->scsi_done(cmd); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected); return; case MESSAGE_REJECT: switch (hostdata->last_message) { case HEAD_OF_QUEUE_TAG: case ORDERED_QUEUE_TAG: case SIMPLE_QUEUE_TAG: scsi_devices[cmd->index].tagged_queue = 0; hostdata->busy[cmd->target] |= (1 << cmd->lun); break; default: break; } case DISCONNECT: scsi_devices[cmd->index].disconnect = 1; cli(); cmd->host_scribble = (unsigned char *) hostdata->disconnected_queue; hostdata->connected = NULL; hostdata->disconnected_queue = cmd; sti();#if (NDEBUG & NDEBUG_QUEUES) printk("scsi%d : command for target %d lun %d was moved from connected to" " the disconnected_queue\n", instance->host_no, cmd->target, cmd->lun);#endif /* Enable reselect interupts */ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); /* Wait for bus free to avoid nasty timeouts */ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected); return; /* * The SCSI data pointer is *IMPLICITLY* saved on a disconnect * operation, in violation of the SCSI spec so we can safely * ignore SAVE/RESTORE pointers calls. * * Unfortunately, some disks violate the SCSI spec and * don't issue the required SAVE_POINTERS message before * disconnecting, and we have to break spec to remain * compatable. */ case SAVE_POINTERS: case RESTORE_POINTERS: break; default:/* * XXX rejected messages should be handled in the pio data transfer phase, * since ATN should be raised before ACK goes false when we reject a message */ printk("Unknown message!\n");#ifdef notyet /* * If we get something wierd that we aren't expecting, * reject it. */ msgout = MESSAGE_REJECT; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);#endif break; } /* switch (tmp) */ break; case PHASE_MSGOUT: len = 1; data = &msgout; hostdata->last_message = msgout; NCR5380_transfer_pio(instance, &phase, &len, &data); if (msgout == ABORT) { hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->connected = NULL; cmd->result = DID_ERROR << 16; cmd->scsi_done(cmd); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return; } msgout = NOP; break; case PHASE_CMDOUT: len = COMMAND_SIZE(cmd->cmnd[0]); data = cmd->cmnd; /* * XXX for performance reasons, on machines with a * PSEUDO-DMA architecture we should probably * use the dma transfer function. */ NCR5380_transfer_pio(instance, &phase, &len, &data);#ifdef USLEEP if (!disconnect && should_disconnect(cmd->cmnd[0])) { hostdata->time_expires = jiffies + USLEEP_SLEEP;#if (NDEBUG & NDEBUG_USLEEP) printk("scsi%d : issued command, sleeping until %ul\n", instance->host_no, hostdata->time_expires);#endif NCR5380_set_timer (instance); return; }#endif /* def USLEEP */ break; case PHASE_STATIN: len = 1; data = &tmp; NCR5380_transfer_pio(instance, &phase, &len, &data); cmd->SCp.Status = tmp; break; default: printk("scsi%d : unknown phase\n", instance->host_no);#ifdef NDEBUG NCR5380_print(instance);#endif } /* switch(phase) */ } /* if (tmp * SR_REQ) */ #ifdef USLEEP else { if (!disconnect && hostdata->time_expires && jiffies > hostdata->time_expires) { hostdata->time_expires = jiffies + USLEEP_SLEEP;#if (NDEBUG & NDEBUG_USLEEP) printk("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, hostdata->time_expires);#endif NCR5380_set_timer (instance); return; } }#endif }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -