📄 53c700.c
字号:
* setting of the SXFER register */ min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock); if(min_period > NCR_700_MIN_PERIOD) { NCR_700_SDTR_msg[3] = min_period; } if(hostdata->chip710) NCR_700_SDTR_msg[4] = NCR_710_MAX_OFFSET;}STATIC voidNCR_700_chip_reset(struct Scsi_Host *host){ struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; if(hostdata->chip710) { NCR_700_writeb(SOFTWARE_RESET_710, host, ISTAT_REG); udelay(100); NCR_700_writeb(0, host, ISTAT_REG); } else { NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG); udelay(100); NCR_700_writeb(0, host, DCNTL_REG); } mdelay(1000); NCR_700_chip_setup(host);}/* The heart of the message processing engine is that the instruction * immediately after the INT is the normal case (and so must be CLEAR * ACK). If we want to do something else, we call that routine in * scripts and set temp to be the normal case + 8 (skipping the CLEAR * ACK) so that the routine returns correctly to resume its activity * */STATIC __u32process_extended_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp, __u32 dsp, __u32 dsps){ __u32 resume_offset = dsp, temp = dsp + 8; __u8 pun = 0xff, lun = 0xff; if(SCp != NULL) { pun = SCp->target; lun = SCp->lun; } switch(hostdata->msgin[2]) { case A_SDTR_MSG: if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) { __u8 period = hostdata->msgin[3]; __u8 offset = hostdata->msgin[4]; __u8 sxfer; if(offset != 0 && period != 0) sxfer = NCR_700_offset_period_to_sxfer(hostdata, offset, period); else sxfer = 0; if(sxfer != NCR_700_get_SXFER(SCp->device)) { printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n", host->host_no, pun, lun, offset, period*4); NCR_700_set_SXFER(SCp->device, sxfer); } NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); NCR_700_writeb(NCR_700_get_SXFER(SCp->device), host, SXFER_REG); } else { /* SDTR message out of the blue, reject it */ printk(KERN_WARNING "scsi%d Unexpected SDTR msg\n", host->host_no); hostdata->msgout[0] = A_REJECT_MSG; NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1); script_patch_16(hostdata->script, MessageCount, 1); /* SendMsgOut returns, so set up the return * address */ resume_offset = hostdata->pScript + Ent_SendMessageWithATN; } break; case A_WDTR_MSG: printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n", host->host_no, pun, lun); hostdata->msgout[0] = A_REJECT_MSG; NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1); script_patch_16(hostdata->script, MessageCount, 1); resume_offset = hostdata->pScript + Ent_SendMessageWithATN; break; default: printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ", host->host_no, pun, lun, NCR_700_phase[(dsps & 0xf00) >> 8]); print_msg(hostdata->msgin); printk("\n"); /* just reject it */ hostdata->msgout[0] = A_REJECT_MSG; NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1); script_patch_16(hostdata->script, MessageCount, 1); /* SendMsgOut returns, so set up the return * address */ resume_offset = hostdata->pScript + Ent_SendMessageWithATN; } NCR_700_writel(temp, host, TEMP_REG); return resume_offset;}STATIC __u32process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp, __u32 dsp, __u32 dsps){ /* work out where to return to */ __u32 temp = dsp + 8, resume_offset = dsp; __u8 pun = 0xff, lun = 0xff; if(SCp != NULL) { pun = SCp->target; lun = SCp->lun; }#ifdef NCR_700_DEBUG printk("scsi%d (%d:%d): message %s: ", host->host_no, pun, lun, NCR_700_phase[(dsps & 0xf00) >> 8]); print_msg(hostdata->msgin); printk("\n");#endif switch(hostdata->msgin[0]) { case A_EXTENDED_MSG: resume_offset = process_extended_message(host, hostdata, SCp, dsp, dsps); break; case A_REJECT_MSG: if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) { /* Rejected our sync negotiation attempt */ NCR_700_set_SXFER(SCp->device, 0); NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); } else if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) { /* rejected our first simple tag message */ printk(KERN_WARNING "scsi%d (%d:%d) Rejected first tag queue attempt, turning off tag queueing\n", host->host_no, pun, lun); NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); hostdata->tag_negotiated &= ~(1<<SCp->target); SCp->device->tagged_queue = 0; SCp->device->tagged_supported = 0; } else { printk(KERN_WARNING "scsi%d (%d:%d) Unexpected REJECT Message %s\n", host->host_no, pun, lun, NCR_700_phase[(dsps & 0xf00) >> 8]); /* however, just ignore it */ } break; case A_PARITY_ERROR_MSG: printk(KERN_ERR "scsi%d (%d:%d) Parity Error!\n", host->host_no, pun, lun); NCR_700_internal_bus_reset(host); break; case A_SIMPLE_TAG_MSG: printk(KERN_INFO "scsi%d (%d:%d) SIMPLE TAG %d %s\n", host->host_no, pun, lun, hostdata->msgin[1], NCR_700_phase[(dsps & 0xf00) >> 8]); /* just ignore it */ break; default: printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ", host->host_no, pun, lun, NCR_700_phase[(dsps & 0xf00) >> 8]); print_msg(hostdata->msgin); printk("\n"); /* just reject it */ hostdata->msgout[0] = A_REJECT_MSG; NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1); script_patch_16(hostdata->script, MessageCount, 1); /* SendMsgOut returns, so set up the return * address */ resume_offset = hostdata->pScript + Ent_SendMessageWithATN; break; } NCR_700_writel(temp, host, TEMP_REG); /* set us up to receive another message */ NCR_700_dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE); return resume_offset;}STATIC __u32process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp, struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata){ __u32 resume_offset = 0; __u8 pun = 0xff, lun=0xff; if(SCp != NULL) { pun = SCp->target; lun = SCp->lun; } if(dsps == A_GOOD_STATUS_AFTER_STATUS) { DEBUG((" COMMAND COMPLETE, status=%02x\n", hostdata->status[0])); /* OK, if TCQ still on, we know it works */ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); /* check for contingent allegiance contitions */ if(status_byte(hostdata->status[0]) == CHECK_CONDITION || status_byte(hostdata->status[0]) == COMMAND_TERMINATED) { struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; if(SCp->cmnd[0] == REQUEST_SENSE) { /* OOPS: bad device, returning another * contingent allegiance condition */ printk(KERN_ERR "scsi%d (%d:%d) broken device is looping in contingent allegiance: ignoring\n", host->host_no, pun, lun); NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]); } else {#ifdef NCR_DEBUG print_command(SCp->cmnd); printk(" cmd %p has status %d, requesting sense\n", SCp, hostdata->status[0]);#endif /* we can destroy the command here * because the contingent allegiance * condition will cause a retry which * will re-copy the command from the * saved data_cmnd. We also unmap any * data associated with the command * here */ NCR_700_unmap(hostdata, SCp, slot); SCp->cmnd[0] = REQUEST_SENSE; SCp->cmnd[1] = (SCp->lun & 0x7) << 5; SCp->cmnd[2] = 0; SCp->cmnd[3] = 0; SCp->cmnd[4] = sizeof(SCp->sense_buffer); SCp->cmnd[5] = 0; SCp->cmd_len = 6; /* Here's a quiet hack: the * REQUEST_SENSE command is six bytes, * so store a flag indicating that * this was an internal sense request * and the original status at the end * of the command */ SCp->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC; SCp->cmnd[7] = hostdata->status[0]; SCp->cmnd[8] = SCp->use_sg; SCp->use_sg = 0; SCp->sc_data_direction = SCSI_DATA_READ; pci_dma_sync_single(hostdata->pci_dev, slot->pCmd, SCp->cmd_len, PCI_DMA_TODEVICE); SCp->request_bufflen = sizeof(SCp->sense_buffer); slot->dma_handle = pci_map_single(hostdata->pci_dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), PCI_DMA_FROMDEVICE); slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer)); slot->SG[0].pAddr = bS_to_host(slot->dma_handle); slot->SG[1].ins = bS_to_host(SCRIPT_RETURN); slot->SG[1].pAddr = 0; slot->resume_offset = hostdata->pScript; NCR_700_dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG[0])*2); NCR_700_dma_cache_inv((unsigned long)SCp->sense_buffer, sizeof(SCp->sense_buffer)); /* queue the command for reissue */ slot->state = NCR_700_SLOT_QUEUED; hostdata->state = NCR_700_HOST_FREE; hostdata->cmd = NULL; } } else { // Currently rely on the mid layer evaluation // of the tag queuing capability // //if(status_byte(hostdata->status[0]) == GOOD && // SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) { // /* Piggy back the tag queueing support // * on this command */ // pci_dma_sync_single(hostdata->pci_dev, // slot->dma_handle, // SCp->request_bufflen, // PCI_DMA_FROMDEVICE); // if(((char *)SCp->request_buffer)[7] & 0x02) { // printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", host->host_no, pun, lun); // hostdata->tag_negotiated |= (1<<SCp->target); // NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); // } else { // NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); // hostdata->tag_negotiated &= ~(1<<SCp->target); // } //} NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]); } } else if((dsps & 0xfffff0f0) == A_UNEXPECTED_PHASE) { __u8 i = (dsps & 0xf00) >> 8; printk(KERN_ERR "scsi%d: (%d:%d), UNEXPECTED PHASE %s (%s)\n", host->host_no, pun, lun, NCR_700_phase[i], sbcl_to_string(NCR_700_readb(host, SBCL_REG))); printk(KERN_ERR " len = %d, cmd =", SCp->cmd_len); print_command(SCp->cmnd); NCR_700_internal_bus_reset(host); } else if((dsps & 0xfffff000) == A_FATAL) { int i = (dsps & 0xfff); printk(KERN_ERR "scsi%d: (%d:%d) FATAL ERROR: %s\n", host->host_no, pun, lun, NCR_700_fatal_messages[i]); if(dsps == A_FATAL_ILLEGAL_MSG_LENGTH) { printk(KERN_ERR " msg begins %02x %02x\n", hostdata->msgin[0], hostdata->msgin[1]); } NCR_700_internal_bus_reset(host); } else if((dsps & 0xfffff0f0) == A_DISCONNECT) {#ifdef NCR_700_DEBUG __u8 i = (dsps & 0xf00) >> 8; printk("scsi%d: (%d:%d), DISCONNECTED (%d) %s\n", host->host_no, pun, lun, i, NCR_700_phase[i]);#endif save_for_reselection(hostdata, SCp, dsp); } else if(dsps == A_RESELECTION_IDENTIFIED) { __u8 lun; struct NCR_700_command_slot *slot; __u8 reselection_id = hostdata->reselection_id; lun = hostdata->msgin[0] & 0x1f; hostdata->reselection_id = 0xff; DEBUG(("scsi%d: (%d:%d) RESELECTED!\n", host->host_no, reselection_id, lun)); /* clear the reselection indicator */ if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) { slot = find_ITLQ_Nexus(hostdata, reselection_id, lun, hostdata->msgin[2]); } else { slot = find_ITL_Nexus(hostdata, reselection_id, lun); } retry: if(slot == NULL) { struct NCR_700_command_slot *s = find_ITL_Nexus(hostdata, reselection_id, lun); printk(KERN_ERR "scsi%d: (%d:%d) RESELECTED but no saved command (MSG = %02x %02x %02x)!!\n", host->host_no, reselection_id, lun, hostdata->msgin[0], hostdata->msgin[1], hostdata->msgin[2]); printk(KERN_ERR " OUTSTANDING TAGS:"); while(s != NULL) { if(s->cmnd->target == reselection_id && s->cmnd->lun == lun) { printk("%d ", s->tag); if(s->tag == hostdata->msgin[2]) { printk(" ***FOUND*** \n"); slot = s; goto retry; } } s = s->ITL_back; } printk("\n"); } else { if(hostdata->state != NCR_700_HOST_BUSY) printk(KERN_ERR "scsi%d: FATAL, host not busy during valid reselection!\n", host->host_no); resume_offset = slot->resume_offset; hostdata->cmd = slot->cmnd; /* re-patch for this command */ script_patch_32_abs(hostdata->script, CommandAddress, slot->pCmd); script_patch_16(hostdata->script, CommandCount, slot->cmnd->cmd_len); script_patch_32_abs(hostdata->script, SGScriptStartAddress, to32bit(&slot->pSG[0].ins)); /* Note: setting SXFER only works if we're * still in the MESSAGE phase, so it is vital * that ACK is still asserted when we process * the reselection message. The resume offset * should therefore always clear ACK */ NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device), host, SXFER_REG); NCR_700_dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -