📄 53c700.c
字号:
continue; SCp = slot->cmnd; printk(KERN_ERR " failing command because of reset, slot %p, cmnd %p\n", slot, SCp); free_slot(slot, hostdata); SCp->host_scribble = NULL; NCR_700_set_depth(SCp->device, 0); /* NOTE: deadlock potential here: we * rely on mid-layer guarantees that * scsi_done won't try to issue the * command again otherwise we'll * deadlock on the * hostdata->state_lock */ SCp->result = DID_RESET << 16; SCp->scsi_done(SCp); } mdelay(25); NCR_700_chip_setup(host); hostdata->state = NCR_700_HOST_FREE; hostdata->cmd = NULL; goto out_unlock; } else if(sstat0 & SELECTION_TIMEOUT) { DEBUG(("scsi%d: (%d:%d) selection timeout\n", host->host_no, pun, lun)); NCR_700_scsi_done(hostdata, SCp, DID_NO_CONNECT<<16); } else if(sstat0 & PHASE_MISMATCH) { struct NCR_700_command_slot *slot = (SCp == NULL) ? NULL : (struct NCR_700_command_slot *)SCp->host_scribble; if(dsp == Ent_SendMessage + 8 + hostdata->pScript) { /* It wants to reply to some part of * our message */#ifdef NCR_700_DEBUG __u32 temp = NCR_700_readl(host, TEMP_REG); int count = (hostdata->script[Ent_SendMessage/4] & 0xffffff) - ((NCR_700_readl(host, DBC_REG) & 0xffffff) + NCR_700_data_residual(host)); printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG)));#endif resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch; } else if(dsp >= to32bit(&slot->pSG[0].ins) && dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) { int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff; int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List); int residual = NCR_700_data_residual(host); int i;#ifdef NCR_700_DEBUG __u32 naddr = NCR_700_readl(host, DNAD_REG); printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x\n", host->host_no, pun, lun, SGcount, data_transfer); print_command(SCp->cmnd); if(residual) { printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x, residual %d\n", host->host_no, pun, lun, SGcount, data_transfer, residual); }#endif data_transfer += residual; if(data_transfer != 0) { int count; __u32 pAddr; SGcount--; count = (bS_to_cpu(slot->SG[SGcount].ins) & 0x00ffffff); DEBUG(("DATA TRANSFER MISMATCH, count = %d, transferred %d\n", count, count-data_transfer)); slot->SG[SGcount].ins &= bS_to_host(0xff000000); slot->SG[SGcount].ins |= bS_to_host(data_transfer); pAddr = bS_to_cpu(slot->SG[SGcount].pAddr); pAddr += (count - data_transfer);#ifdef NCR_700_DEBUG if(pAddr != naddr) { printk("scsi%d (%d:%d) transfer mismatch pAddr=%lx, naddr=%lx, data_transfer=%d, residual=%d\n", host->host_no, pun, lun, (unsigned long)pAddr, (unsigned long)naddr, data_transfer, residual); }#endif slot->SG[SGcount].pAddr = bS_to_host(pAddr); } /* set the executed moves to nops */ for(i=0; i<SGcount; i++) { slot->SG[i].ins = bS_to_host(SCRIPT_NOP); slot->SG[i].pAddr = 0; } NCR_700_dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG)); /* and pretend we disconnected after * the command phase */ resume_offset = hostdata->pScript + Ent_MsgInDuringData; /* make sure all the data is flushed */ NCR_700_flush_fifo(host); } else { __u8 sbcl = NCR_700_readb(host, SBCL_REG); printk(KERN_ERR "scsi%d: (%d:%d) phase mismatch at %04x, phase %s\n", host->host_no, pun, lun, dsp - hostdata->pScript, sbcl_to_string(sbcl)); NCR_700_internal_bus_reset(host); } } else if(sstat0 & SCSI_GROSS_ERROR) { printk(KERN_ERR "scsi%d: (%d:%d) GROSS ERROR\n", host->host_no, pun, lun); NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); } else if(sstat0 & PARITY_ERROR) { printk(KERN_ERR "scsi%d: (%d:%d) PARITY ERROR\n", host->host_no, pun, lun); NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); } else if(dstat & SCRIPT_INT_RECEIVED) { DEBUG(("scsi%d: (%d:%d) ====>SCRIPT INTERRUPT<====\n", host->host_no, pun, lun)); resume_offset = process_script_interrupt(dsps, dsp, SCp, host, hostdata); } else if(dstat & (ILGL_INST_DETECTED)) { printk(KERN_ERR "scsi%d: (%d:%d) Illegal Instruction detected at 0x%08x[0x%x]!!!\n" " Please email James.Bottomley@HansenPartnership.com with the details\n", host->host_no, pun, lun, dsp, dsp - hostdata->pScript); NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); } else if(dstat & (WATCH_DOG_INTERRUPT|ABORTED)) { printk(KERN_ERR "scsi%d: (%d:%d) serious DMA problem, dstat=%02x\n", host->host_no, pun, lun, dstat); NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); } /* NOTE: selection interrupt processing MUST occur * after script interrupt processing to correctly cope * with the case where we process a disconnect and * then get reselected before we process the * disconnection */ if(sstat0 & SELECTED) { /* FIXME: It currently takes at least FOUR * interrupts to complete a command that * disconnects: one for the disconnect, one * for the reselection, one to get the * reselection data and one to complete the * command. If we guess the reselected * command here and prepare it, we only need * to get a reselection data interrupt if we * guessed wrongly. Since the interrupt * overhead is much greater than the command * setup, this would be an efficient * optimisation particularly as we probably * only have one outstanding command on a * target most of the time */ resume_offset = process_selection(host, dsp); } } if(resume_offset) { if(hostdata->state != NCR_700_HOST_BUSY) { printk(KERN_ERR "scsi%d: Driver error: resume at 0x%08x [0x%04x] with non busy host!\n", host->host_no, resume_offset, resume_offset - hostdata->pScript); hostdata->state = NCR_700_HOST_BUSY; } DEBUG(("Attempting to resume at %x\n", resume_offset)); NCR_700_clear_fifo(host); NCR_700_writel(resume_offset, host, DSP_REG); } /* There is probably a technical no-no about this: If we're a * shared interrupt and we got this interrupt because the * other device needs servicing not us, we're still going to * check our queued commands here---of course, there shouldn't * be any outstanding.... */ if(hostdata->state == NCR_700_HOST_FREE) { int i; for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) { /* fairness: always run the queue from the last * position we left off */ int j = (i + hostdata->saved_slot_position) % NCR_700_COMMAND_SLOTS_PER_HOST; if(hostdata->slots[j].state != NCR_700_SLOT_QUEUED) continue; if(NCR_700_start_command(hostdata->slots[j].cmnd)) { DEBUG(("scsi%d: Issuing saved command slot %p, cmd %p\t\n", host->host_no, &hostdata->slots[j], hostdata->slots[j].cmnd)); hostdata->saved_slot_position = j + 1; } break; } } out_unlock: spin_unlock_irqrestore(&io_request_lock, flags);}/* FIXME: Need to put some proc information in and plumb it * into the scsi proc system */STATIC intNCR_700_proc_directory_info(char *proc_buf, char **startp, off_t offset, int bytes_available, int host_no, int write){ static char buf[4096]; /* 1 page should be sufficient */ int len = 0; struct Scsi_Host *host = scsi_hostlist; struct NCR_700_Host_Parameters *hostdata; Scsi_Device *SDp; while(host != NULL && host->host_no != host_no) host = host->next; if(host == NULL) return 0; if(write) { /* FIXME: Clear internal statistics here */ return 0; } hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; len += sprintf(&buf[len], "Total commands outstanding: %d\n", hostdata->command_slot_count); len += sprintf(&buf[len],"\Target Depth Active Next Tag\n\====== ===== ====== ========\n"); for(SDp = host->host_queue; SDp != NULL; SDp = SDp->next) { len += sprintf(&buf[len]," %2d:%2d %4d %4d %4d\n", SDp->id, SDp->lun, SDp->queue_depth, NCR_700_get_depth(SDp), SDp->current_tag); } if((len -= offset) <= 0) return 0; if(len > bytes_available) len = bytes_available; memcpy(proc_buf, buf + offset, len); return len;}STATIC intNCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *)){ struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SCp->host->hostdata[0]; __u32 move_ins; int pci_direction; struct NCR_700_command_slot *slot; int hash; if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) { /* We're over our allocation, this should never happen * since we report the max allocation to the mid layer */ printk(KERN_WARNING "scsi%d: Command depth has gone over queue depth\n", SCp->host->host_no); return 1; } if(NCR_700_get_depth(SCp->device) != 0 && !(hostdata->tag_negotiated & (1<<SCp->target))) { DEBUG((KERN_ERR "scsi%d (%d:%d) has non zero depth %d\n", SCp->host->host_no, SCp->target, SCp->lun, NCR_700_get_depth(SCp->device))); return 1; } if(NCR_700_get_depth(SCp->device) >= NCR_700_MAX_TAGS) { DEBUG((KERN_ERR "scsi%d (%d:%d) has max tag depth %d\n", SCp->host->host_no, SCp->target, SCp->lun, NCR_700_get_depth(SCp->device))); return 1; } NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) + 1); /* begin the command here */ /* no need to check for NULL, test for command_slot_cound above * ensures a slot is free */ slot = find_empty_slot(hostdata); slot->cmnd = SCp; SCp->scsi_done = done; SCp->host_scribble = (unsigned char *)slot; SCp->SCp.ptr = NULL; SCp->SCp.buffer = NULL;#ifdef NCR_700_DEBUG printk("53c700: scsi%d, command ", SCp->host->host_no); print_command(SCp->cmnd);#endif if(SCp->device->tagged_supported && !SCp->device->tagged_queue && (hostdata->tag_negotiated &(1<<SCp->target)) == 0 && NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) { /* upper layer has indicated tags are supported. We don't * necessarily believe it yet. * * NOTE: There is a danger here: the mid layer supports * tag queuing per LUN. We only support it per PUN because * of potential reselection issues */ printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->target, SCp->lun); hostdata->tag_negotiated |= (1<<SCp->target); NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); SCp->device->tagged_queue = 1; } if(hostdata->tag_negotiated &(1<<SCp->target)) { struct NCR_700_command_slot *old = find_ITL_Nexus(hostdata, SCp->target, SCp->lun);#ifdef NCR_700_TAG_DEBUG struct NCR_700_command_slot *found;#endif if(old != NULL && old->tag == SCp->device->current_tag) { /* On some badly starving drives, this can be * a frequent occurance, so print the message * only once */ if(NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_TAG_STARVATION_WARNED)) { printk(KERN_WARNING "scsi%d (%d:%d) Target is suffering from tag starvation.\n", SCp->host->host_no, SCp->target, SCp->lun); NCR_700_set_flag(SCp->device, NCR_700_DEV_TAG_STARVATION_WARNED); } return 1; } slot->tag = SCp->device->current_tag++;#ifdef NCR_700_TAG_DEBUG while((found = find_ITLQ_Nexus(hostdata, SCp->target, SCp->lun, slot->tag)) != NULL) { printk("\n\n**ERROR** already using tag %d, but oldest is %d\n", slot->tag, (old == NULL) ? -1 : old->tag); printk(" FOUND = %p, tag = %d, pun = %d, lun = %d\n", found, found->tag, found->cmnd->target, found->cmnd->lun); slot->tag = SCp->device->current_tag++; printk(" Tag list is: "); while(old != NULL) { if(old->cmnd->target == SCp->target && old->cmnd->lun == SCp->lun) printk("%d ", old->tag); old = old->ITL_back; } printk("\n\n"); }#endif hash = hash_ITLQ(SCp->target, SCp->lun, slot->tag); /* link into the ITLQ hash queues */ slot->ITLQ_forw = hostdata->ITLQ_Hash_forw[hash]; hostdata->ITLQ_Hash_forw[hash] = slot;#ifdef NCR_700_TAG_DEBUG if(slot->ITLQ_forw != NULL && slot->ITLQ_forw->ITLQ_back != NULL) { printk(KERN_ERR "scsi%d (%d:%d) ITLQ_back is not NULL!!!!\n", SCp->host->host_no, SCp->target, SCp->lun); }#endif if(slot->ITLQ_forw != NULL) slot->ITLQ_forw->ITLQ_back = slot; else hostdata->ITLQ_Hash_back[hash] = slot; slot->ITLQ_back = NULL; } else { slot->tag = NCR_700_NO_TAG; } /* link into the ITL hash queues */ hash = hash_ITL(SCp->target, SCp->lun); slot->ITL_forw = hostdata->ITL_Hash_forw[hash]; hostdata->ITL_Hash_forw[hash] = slot;#ifdef NCR_700_TAG_DEBUG if(slot->ITL_forw != NULL && slot->ITL_forw->ITL_back != NULL) { printk(KERN_ERR "scsi%d (%d:%d) ITL_back is not NULL!!!!\n", SCp->host->host_no, SCp->target, SCp->lun); }#endif if(slot->ITL_forw != NULL) slot->ITL_forw->ITL_back = slot; else hostdata->ITL_Hash_back[hash] = slot; slot->ITL_back = NULL; /* sanity check: some of the commands generated by the mid-layer * have an eccentric idea of their sc_data_direction */ if(!SCp->use_sg && !SCp->request_bufflen && SCp->sc_data_direction != SCSI_DATA_NONE) {#ifdef NCR_700_DEBUG printk("53c700: Command"); print_command(SCp->cmnd); printk("Has wrong data direction %d\n", SCp->sc_data_direction);#endif SCp->sc_data_direction = SCSI_DATA_NONE; } switch (SCp->cmnd[0]) { case REQUEST_SENSE: /* clear the internal sense magic */ SCp->cmnd[6] = 0; /* fall through */ default: /* OK, get it from the command */ switch(SCp->sc_data_direction) { case SCSI_DATA_UNKNOWN: default: printk(KERN_ERR "53c700: Unknown command for data direction "); print_command(SCp->cmnd); move_ins = 0; break; case SCSI_DATA_NONE: move_ins = 0; break; case SCSI_DATA_READ: move_ins = SCRIPT_MOVE_DATA_IN; break; case SCSI_DATA_WRITE:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -