📄 ncr53c9x.c
字号:
break; case fas216: case fas236: case fsc: /* Fast ESP variants */ esp_write(eregs->esp_cfg2, esp->config2); for(i=0; i<8; i++) esp->config3[i] |= ESP_CONFIG3_FCLK; esp->prev_cfg3 = esp->config3[0]; esp_write(eregs->esp_cfg3, esp->prev_cfg3); if(esp->diff) esp->radelay = 0; else esp->radelay = 16; /* Different timeout constant for these chips */ esp->neg_defp = FSC_NEG_DEFP(esp->cfreq, (esp->cfact == ESP_CCF_F0 ? ESP_CCF_F7 + 1 : esp->cfact)); esp_write(eregs->esp_timeo, esp->neg_defp); /* Enable Active Negotiation if possible */ if((esp->erev == fsc) && !esp->diff) esp_write(eregs->esp_cfg4, ESP_CONFIG4_EAN); break; case fas100a: /* Fast 100a */ esp_write(eregs->esp_cfg2, esp->config2); for(i=0; i<8; i++) esp->config3[i] |= ESP_CONFIG3_FCLOCK; esp->prev_cfg3 = esp->config3[0]; esp_write(eregs->esp_cfg3, esp->prev_cfg3); esp->radelay = 32; break; default: panic("esp: what could it be... I wonder..."); break; }; /* Eat any bitrot in the chip */ trash = esp_read(eregs->esp_intrpt); udelay(100);}/* This places the ESP into a known state at boot time. */void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs){ volatile unchar trash; /* Reset the DMA */ if(esp->dma_reset) esp->dma_reset(esp); /* Reset the ESP */ esp_reset_esp(esp, eregs); /* Reset the SCSI bus, but tell ESP not to generate an irq */ esp_write(eregs->esp_cfg1, (esp_read(eregs->esp_cfg1) | ESP_CONFIG1_SRRDISAB)); esp_cmd(esp, eregs, ESP_CMD_RS); udelay(400); esp_write(eregs->esp_cfg1, esp->config1); /* Eat any bitrot in the chip and we are done... */ trash = esp_read(eregs->esp_intrpt);}/* Allocate structure and insert basic data such as SCSI chip frequency * data and a pointer to the device */struct NCR_ESP* esp_allocate(Scsi_Host_Template *tpnt, void *esp_dev){ struct NCR_ESP *esp, *elink; struct Scsi_Host *esp_host; esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP)); if(!esp_host) panic("Cannot register ESP SCSI host"); esp = (struct NCR_ESP *) esp_host->hostdata; if(!esp) panic("No esp in hostdata"); esp->ehost = esp_host; esp->edev = esp_dev; esp->esp_id = nesps++; /* Set bitshift value (only used on Amiga with multiple ESPs) */ esp->shift = 2; /* Put into the chain of esp chips detected */ if(espchain) { elink = espchain; while(elink->next) elink = elink->next; elink->next = esp; } else { espchain = esp; } esp->next = 0; return esp;}void esp_deallocate(struct NCR_ESP *esp){ struct NCR_ESP *elink; if(espchain == esp) { espchain = 0; } else { for(elink = espchain; elink && (elink->next != esp); elink = elink->next); if(elink) elink->next = esp->next; } nesps--;}/* Complete initialization of ESP structure and device * Caller must have initialized appropriate parts of the ESP structure * between the call to esp_allocate and this function. */void esp_initialize(struct NCR_ESP *esp){ struct ESP_regs *eregs = esp->eregs; unsigned int fmhz; unchar ccf; int i; /* Check out the clock properties of the chip. */ /* This is getting messy but it has to be done * correctly or else you get weird behavior all * over the place. We are trying to basically * figure out three pieces of information. * * a) Clock Conversion Factor * * This is a representation of the input * crystal clock frequency going into the * ESP on this machine. Any operation whose * timing is longer than 400ns depends on this * value being correct. For example, you'll * get blips for arbitration/selection during * high load or with multiple targets if this * is not set correctly. * * b) Selection Time-Out * * The ESP isn't very bright and will arbitrate * for the bus and try to select a target * forever if you let it. This value tells * the ESP when it has taken too long to * negotiate and that it should interrupt * the CPU so we can see what happened. * The value is computed as follows (from * NCR/Symbios chip docs). * * (Time Out Period) * (Input Clock) * STO = ---------------------------------- * (8192) * (Clock Conversion Factor) * * You usually want the time out period to be * around 250ms, I think we'll set it a little * bit higher to account for fully loaded SCSI * bus's and slow devices that don't respond so * quickly to selection attempts. (yeah, I know * this is out of spec. but there is a lot of * buggy pieces of firmware out there so bite me) * * c) Imperical constants for synchronous offset * and transfer period register values * * This entails the smallest and largest sync * period we could ever handle on this ESP. */ fmhz = esp->cfreq; if(fmhz <= (5000000)) ccf = 0; else ccf = (((5000000 - 1) + (fmhz))/(5000000)); if(!ccf || ccf > 8) { /* If we can't find anything reasonable, * just assume 20MHZ. This is the clock * frequency of the older sun4c's where I've * been unable to find the clock-frequency * PROM property. All other machines provide * useful values it seems. */ ccf = ESP_CCF_F4; fmhz = (20000000); } if(ccf==(ESP_CCF_F7+1)) esp->cfact = ESP_CCF_F0; else if(ccf == ESP_CCF_NEVER) esp->cfact = ESP_CCF_F2; else esp->cfact = ccf; esp->cfreq = fmhz; esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz); esp->ctick = ESP_TICK(ccf, esp->ccycle); esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf); esp->sync_defp = SYNC_DEFP_SLOW; printk("SCSI ID %d Clk %dMHz CCF=%d TOut %d ", esp->scsi_id, (esp->cfreq / 1000000), ccf, (int) esp->neg_defp); /* Fill in ehost data */ esp->ehost->base = (unsigned long)eregs; esp->ehost->this_id = esp->scsi_id; esp->ehost->irq = esp->irq; /* SCSI id mask */ esp->scsi_id_mask = (1 << esp->scsi_id); /* Probe the revision of this esp */ esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7)); esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY); esp_write(eregs->esp_cfg2, esp->config2); if((esp_read(eregs->esp_cfg2) & ~(ESP_CONFIG2_MAGIC)) != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { printk("NCR53C90(esp100)\n"); esp->erev = esp100; } else { esp->config2 = 0; esp_write(eregs->esp_cfg2, 0); esp_write(eregs->esp_cfg3, 5); if(esp_read(eregs->esp_cfg3) != 5) { printk("NCR53C90A(esp100a)\n"); esp->erev = esp100a; } else { int target; for(target=0; target<8; target++) esp->config3[target] = 0; esp->prev_cfg3 = 0; esp_write(eregs->esp_cfg3, 0); if(ccf > ESP_CCF_F5) { printk("NCR53C9XF(espfast)\n"); esp->erev = fast; esp->sync_defp = SYNC_DEFP_FAST; } else { printk("NCR53C9x(esp236)\n"); esp->erev = esp236; } } } /* Initialize the command queues */ esp->current_SC = 0; esp->disconnected_SC = 0; esp->issue_SC = 0; /* Clear the state machines. */ esp->targets_present = 0; esp->resetting_bus = 0; esp->snip = 0; esp->fas_premature_intr_workaround = 0; for(i = 0; i < 32; i++) esp->espcmdlog[i] = 0; esp->espcmdent = 0; for(i = 0; i < 16; i++) { esp->cur_msgout[i] = 0; esp->cur_msgin[i] = 0; } esp->prevmsgout = esp->prevmsgin = 0; esp->msgout_len = esp->msgin_len = 0; /* Clear the one behind caches to hold unmatchable values. */ esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff; /* Reset the thing before we try anything... */ esp_bootup_reset(esp, eregs);#ifdef MODULE MOD_INC_USE_COUNT;#endif esps_in_use++;}/* The info function will return whatever useful * information the developer sees fit. If not provided, then * the name field will be used instead. */const char *esp_info(struct Scsi_Host *host){ struct NCR_ESP *esp; esp = (struct NCR_ESP *) host->hostdata; switch(esp->erev) { case esp100: return "ESP100 (NCR53C90)"; case esp100a: return "ESP100A (NCR53C90A)"; case esp236: return "ESP236 (NCR53C9x)"; case fas216: return "Emulex FAS216"; case fas236: return "Emulex FAS236"; case fas366: return "QLogic FAS366"; case fas100a: return "FPESP100A"; case fsc: return "Symbios Logic 53CF9x-2"; default: panic("Bogon ESP revision"); };}/* From Wolfgang Stanglmeier's NCR scsi driver. */struct info_str{ char *buffer; int length; int offset; int pos;};static void copy_mem_info(struct info_str *info, char *data, int len){ if (info->pos + len > info->length) len = info->length - info->pos; if (info->pos + len < info->offset) { info->pos += len; return; } if (info->pos < info->offset) { data += (info->offset - info->pos); len -= (info->offset - info->pos); } if (len > 0) { memcpy(info->buffer + info->pos, data, len); info->pos += len; }}static int copy_info(struct info_str *info, char *fmt, ...){ va_list args; char buf[81]; int len; va_start(args, fmt); len = vsprintf(buf, fmt, args); va_end(args); copy_mem_info(info, buf, len); return len;}static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len){ struct info_str info; int i; info.buffer = ptr; info.length = len; info.offset = offset; info.pos = 0; copy_info(&info, "ESP Host Adapter:\n"); copy_info(&info, "\tESP Model\t\t"); switch(esp->erev) { case esp100: copy_info(&info, "ESP100 (NCR53C90)\n"); break; case esp100a: copy_info(&info, "ESP100A (NCR53C90A)\n"); break; case esp236: copy_info(&info, "ESP236 (NCR53C9x)\n"); break; case fas216: copy_info(&info, "Emulex FAS216\n"); break; case fas236: copy_info(&info, "Emulex FAS236\n"); break; case fas100a: copy_info(&info, "FPESP100A\n"); break; case fast: copy_info(&info, "Generic FAST\n"); break; case fas366: copy_info(&info, "QLogic FAS366\n"); break; case fsc: copy_info(&info, "Symbios Logic 53C9x-2\n"); break; case espunknown: default: copy_info(&info, "Unknown!\n"); break; }; copy_info(&info, "\tLive Targets\t\t[ "); for(i = 0; i < 15; i++) { if(esp->targets_present & (1 << i)) copy_info(&info, "%d ", i); } copy_info(&info, "]\n\n"); /* Now describe the state of each existing target. */ copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\n"); for(i = 0; i < 15; i++) { if(esp->targets_present & (1 << i)) { Scsi_Device *SDptr = esp->ehost->host_queue; while((SDptr->host != esp->ehost) && (SDptr->id != i) && (SDptr->next)) SDptr = SDptr->next; copy_info(&info, "%d\t\t", i); copy_info(&info, "%08lx\t", esp->config3[i]); copy_info(&info, "[%02lx,%02lx]\t\t\t", SDptr->sync_max_offset, SDptr->sync_min_period); copy_info(&info, "%s\n", SDptr->disconnect ? "yes" : "no"); } } return info.pos > info.offset? info.pos - info.offset : 0;}/* ESP proc filesystem code. */int esp_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout){ struct NCR_ESP *esp; if(inout) return -EINVAL; /* not yet */ for_each_esp(esp) { if(esp->ehost->host_no == hostno) break; } if(!esp) return -EINVAL; if(start) *start = buffer; return esp_host_info(esp, buffer, offset, length);}static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp){ if(sp->use_sg == 0) { sp->SCp.this_residual = sp->request_bufflen; sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; sp->SCp.buffers_residual = 0; if (esp->dma_mmu_get_scsi_one) esp->dma_mmu_get_scsi_one(esp, sp); else sp->SCp.have_data_in = (int) sp->SCp.ptr = (char *) virt_to_phys(sp->request_buffer); } else { sp->SCp.buffer = (struct scatterlist *) sp->buffer; sp->SCp.buffers_residual = sp->use_sg - 1; sp->SCp.this_residual = sp->SCp.buffer->length; if (esp->dma_mmu_get_scsi_sgl)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -