📄 53c7,8xx.c
字号:
* Purpose : Initialize internal structures, as required on startup, or * after a SCSI bus reset. * * Inputs : host - pointer to this host adapter's structure */static void NCR53c7x0_driver_init (struct Scsi_Host *host) { struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata; int i, j; u32 *curr; for (i = 0; i < 16; ++i) { hostdata->request_sense[i] = 0; for (j = 0; j < 8; ++j) hostdata->busy[i][j] = 0; set_synchronous (host, i, /* sxfer */ 0, hostdata->saved_scntl3, 0); } hostdata->issue_queue = NULL; hostdata->running_list = hostdata->finished_queue = hostdata->curr = NULL; for (i = 0, curr = (u32 *) hostdata->schedule; i < host->can_queue; ++i, curr += 2) { curr[0] = hostdata->NOP_insn; curr[1] = le32_to_cpu(0xdeadbeef); } curr[0] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE); curr[1] = (u32) le32_to_cpu(virt_to_bus (hostdata->script) + hostdata->E_wait_reselect); hostdata->reconnect_dsa_head = 0; hostdata->addr_reconnect_dsa_head = (u32) le32_to_cpu(virt_to_bus((void *) &(hostdata->reconnect_dsa_head))); hostdata->expecting_iid = 0; hostdata->expecting_sto = 0; if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS) hostdata->initiate_sdtr = le32_to_cpu(0xffff); else hostdata->initiate_sdtr = 0; hostdata->talked_to = 0; hostdata->idle = 1;}/* * Function : static int ccf_to_clock (int ccf) * * Purpose : Return the largest SCSI clock allowable for a given * clock conversion factor, allowing us to do synchronous periods * when we don't know what the SCSI clock is by taking at least * as long as the device says we can. * * Inputs : ccf * * Returns : clock on success, -1 on failure. */static int ccf_to_clock (int ccf) { switch (ccf) { case 1: return 25000000; /* Divide by 1.0 */ case 2: return 37500000; /* Divide by 1.5 */ case 3: return 50000000; /* Divide by 2.0 */ case 0: /* Divide by 3.0 */ case 4: return 66000000; default: return -1; }}/* * Function : static int clock_to_ccf (int clock) * * Purpose : Return the clock conversion factor for a given SCSI clock. * * Inputs : clock - SCSI clock expressed in Hz. * * Returns : ccf on success, -1 on failure. */static int clock_to_ccf (int clock) { if (clock < 16666666) return -1; if (clock < 25000000) return 1; /* Divide by 1.0 */ else if (clock < 37500000) return 2; /* Divide by 1.5 */ else if (clock < 50000000) return 3; /* Divide by 2.0 */ else if (clock < 66000000) return 4; /* Divide by 3.0 */ else return -1;} /* * Function : static int NCR53c7x0_init (struct Scsi_Host *host) * * Purpose : initialize the internal structures for a given SCSI host * * Inputs : host - pointer to this host adapter's structure * * Preconditions : when this function is called, the chip_type * field of the hostdata structure MUST have been set. * * Returns : 0 on success, -1 on failure. */static int NCR53c7x0_init (struct Scsi_Host *host) { NCR53c7x0_local_declare(); int i, ccf, expected_ccf; struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata; struct Scsi_Host *search; /* * There are some things which we need to know about in order to provide * a semblance of support. Print 'em if they aren't what we expect, * otherwise don't add to the noise. * * -1 means we don't know what to expect. */ int expected_id = -1; int expected_clock = -1; int uninitialized = 0; /* * FIXME : this is only on Intel boxes. On other platforms, this * will differ. */ int expected_mapping = OPTION_IO_MAPPED; NCR53c7x0_local_setup(host); switch (hostdata->chip) { case 820: case 825:#ifdef notyet host->max_id = 15;#endif /* Fall through */ case 810: case 815: hostdata->dstat_sir_intr = NCR53c8x0_dstat_sir_intr; hostdata->init_save_regs = NULL; hostdata->dsa_fixup = NCR53c8xx_dsa_fixup; hostdata->init_fixup = NCR53c8x0_init_fixup; hostdata->soft_reset = NCR53c8x0_soft_reset; hostdata->run_tests = NCR53c8xx_run_tests;/* Is the SCSI clock ever anything else on these chips? */ expected_clock = hostdata->scsi_clock = 40000000; expected_id = 7; break; default: printk ("scsi%d : chip type of %d is not supported yet, detaching.\n", host->host_no, hostdata->chip); scsi_unregister (host); return -1; } /* Assign constants accessed by NCR */ hostdata->NCR53c7xx_zero = 0; hostdata->NCR53c7xx_msg_reject = le32_to_cpu(MESSAGE_REJECT); hostdata->NCR53c7xx_msg_abort = le32_to_cpu(ABORT); hostdata->NCR53c7xx_msg_nop = le32_to_cpu(NOP); hostdata->NOP_insn = le32_to_cpu((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24); if (expected_mapping == -1 || (hostdata->options & (OPTION_MEMORY_MAPPED)) != (expected_mapping & OPTION_MEMORY_MAPPED)) printk ("scsi%d : using %s mapped access\n", host->host_no, (hostdata->options & OPTION_MEMORY_MAPPED) ? "memory" : "io"); hostdata->dmode = (hostdata->chip == 700 || hostdata->chip == 70066) ? DMODE_REG_00 : DMODE_REG_10; hostdata->istat = ((hostdata->chip / 100) == 8) ? ISTAT_REG_800 : ISTAT_REG_700;/* Only the ISTAT register is readable when the NCR is running, so make sure it's halted. */ ncr_halt(host);/* * XXX - the NCR53c700 uses bitfielded registers for SCID, SDID, etc, * as does the 710 with one bit per SCSI ID. Conversely, the NCR * uses a normal, 3 bit binary representation of these values. * * Get the rest of the NCR documentation, and FIND OUT where the change * was. */#if 0 tmp = hostdata->this_id_mask = NCR53c7x0_read8(SCID_REG); for (host->this_id = 0; tmp != 1; tmp >>=1, ++host->this_id);#else host->this_id = NCR53c7x0_read8(SCID_REG) & 15; if (host->this_id == 0) host->this_id = 7; /* sanitize hostid---0 doesn't make sense */ hostdata->this_id_mask = 1 << host->this_id;#endif/* * Note : we should never encounter a board setup for ID0. So, * if we see ID0, assume that it was uninitialized and set it * to the industry standard 7. */ if (!host->this_id) { printk("scsi%d : initiator ID was %d, changing to 7\n", host->host_no, host->this_id); host->this_id = 7; hostdata->this_id_mask = 1 << 7; uninitialized = 1; }; if (expected_id == -1 || host->this_id != expected_id) printk("scsi%d : using initiator ID %d\n", host->host_no, host->this_id); /* * Save important registers to allow a soft reset. */ if ((hostdata->chip / 100) == 8) { /* * CTEST4 controls burst mode disable. */ hostdata->saved_ctest4 = NCR53c7x0_read8(CTEST4_REG_800) & CTEST4_800_SAVE; } else { /* * CTEST7 controls cache snooping, burst mode, and support for * external differential drivers. */ hostdata->saved_ctest7 = NCR53c7x0_read8(CTEST7_REG) & CTEST7_SAVE; } /* * On NCR53c700 series chips, DCNTL controls the SCSI clock divisor, * on 800 series chips, it allows for a totem-pole IRQ driver. */ hostdata->saved_dcntl = NCR53c7x0_read8(DCNTL_REG); /* * DCNTL_800_IRQM controls weather we are using an open drain * driver (reset) or totem pole driver (set). In all cases, * it's level active. I suppose this is an issue when we're trying to * wire-or the same PCI INTx line? */ if ((hostdata->chip / 100) == 8) hostdata->saved_dcntl &= ~DCNTL_800_IRQM; /* * DMODE controls DMA burst length, and on 700 series chips, * 286 mode and bus width */ hostdata->saved_dmode = NCR53c7x0_read8(hostdata->dmode); /* * Now that burst length and enabled/disabled status is known, * clue the user in on it. */ if ((hostdata->chip / 100) == 8) { if (hostdata->saved_ctest4 & CTEST4_800_BDIS) { printk ("scsi%d : burst mode disabled\n", host->host_no); } else { switch (hostdata->saved_dmode & DMODE_BL_MASK) { case DMODE_BL_2: i = 2; break; case DMODE_BL_4: i = 4; break; case DMODE_BL_8: i = 8; break; case DMODE_BL_16: i = 16; break; default: i = 0; } printk ("scsi%d : burst length %d\n", host->host_no, i); } } /* * On NCR53c810 and NCR53c820 chips, SCNTL3 contails the synchronous * and normal clock conversion factors. */ if (hostdata->chip / 100 == 8) { expected_ccf = clock_to_ccf (expected_clock); hostdata->saved_scntl3 = NCR53c7x0_read8(SCNTL3_REG_800); ccf = hostdata->saved_scntl3 & SCNTL3_800_CCF_MASK; if (expected_ccf != -1 && ccf != expected_ccf && !ccf) { hostdata->saved_scntl3 = (hostdata->saved_scntl3 & ~SCNTL3_800_CCF_MASK) | expected_ccf; if (!uninitialized) { printk ("scsi%d : reset ccf to %d from %d\n", host->host_no, expected_ccf, ccf); uninitialized = 1; } } } else ccf = 0; /* * If we don't have a SCSI clock programmed, pick one on the upper * bound of that allowed by NCR so that our transfers err on the * slow side, since transfer period must be >= the agreed * upon period. */ if ((!hostdata->scsi_clock) && (hostdata->scsi_clock = ccf_to_clock (ccf)) == -1) { printk ("scsi%d : clock conversion factor %d unknown.\n" " synchronous transfers disabled\n", host->host_no, ccf); hostdata->options &= ~OPTION_SYNCHRONOUS; hostdata->scsi_clock = 0; } if (expected_clock == -1 || hostdata->scsi_clock != expected_clock) printk ("scsi%d : using %dMHz SCSI clock\n", host->host_no, hostdata->scsi_clock / 1000000); for (i = 0; i < 16; ++i) hostdata->cmd_allocated[i] = 0; if (hostdata->init_save_regs) hostdata->init_save_regs (host); if (hostdata->init_fixup) hostdata->init_fixup (host); if (!the_template) { the_template = host->hostt; first_host = host; } /* * Linux SCSI drivers have always been plagued with initialization * problems - some didn't work with the BIOS disabled since they expected * initialization from it, some didn't work when the networking code * was enabled and registers got scrambled, etc. * * To avoid problems like this, in the future, we will do a soft * reset on the SCSI chip, taking it back to a sane state. */ hostdata->soft_reset (host);#if 1 hostdata->debug_count_limit = -1;#else hostdata->debug_count_limit = 1;#endif hostdata->intrs = -1; hostdata->resets = -1; memcpy ((void *) hostdata->synchronous_want, (void *) sdtr_message, sizeof (hostdata->synchronous_want)); NCR53c7x0_driver_init (host); /* * Set up an interrupt handler if we aren't already sharing an IRQ * with another board. */ for (search = first_host; search && !(search->hostt == the_template && search->irq == host->irq && search != host); search=search->next); if (!search) {#ifdef __powerpc__ if (request_irq(host->irq, do_NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL)) #else if (request_irq(host->irq, do_NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))#endif { printk("scsi%d : IRQ%d not free, detaching\n" " You have either a configuration problem, or a\n" " broken BIOS. You may wish to manually assign\n" " an interrupt to the NCR board rather than using\n" " an automatic setting.\n", host->host_no, host->irq); scsi_unregister (host); return -1; } } else { printk("scsi%d : using interrupt handler previously installed for scsi%d\n", host->host_no, search->host_no); } if ((hostdata->run_tests && hostdata->run_tests(host) == -1) || (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) { /* XXX Should disable interrupts, etc. here */ scsi_unregister (host);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -