📄 53c7,8xx.c
字号:
* Purpose : detects and initializes NCR53c7,8x0 SCSI chips * that were autoprobed, overridden on the LILO command line, * or specified at compile time. * * Inputs : tpnt - template for this SCSI adapter * * Returns : number of host adapters detected * */__initfunc(int NCR53c7xx_detect(Scsi_Host_Template *tpnt)) { int i; int current_override; int count; /* Number of boards detected */ unsigned char pci_bus, pci_device_fn; static short pci_index=0; /* Device index to PCI BIOS calls */#ifndef LINUX_1_2 tpnt->proc_dir = &proc_scsi_ncr53c7xx;#endif for (current_override = count = 0; current_override < OVERRIDE_LIMIT; ++current_override) { if (overrides[current_override].pci ? !ncr_pci_init (tpnt, overrides[current_override].board, overrides[current_override].chip, (unsigned char) overrides[current_override].data.pci.bus, (((overrides[current_override].data.pci.device << 3) & 0xf8)|(overrides[current_override].data.pci.function & 7)), overrides[current_override].options): !normal_init (tpnt, overrides[current_override].board, overrides[current_override].chip, overrides[current_override].data.normal.base, overrides[current_override].data.normal.io_port, overrides[current_override].data.normal.irq, overrides[current_override].data.normal.dma, 0 /* PCI data invalid */, 0 /* PCI bus place holder */, 0 /* PCI device_function place holder */, overrides[current_override].options)) { ++count; } } if (pci_present()) { for (i = 0; i < NPCI_CHIP_IDS; ++i) for (pci_index = 0; !pcibios_find_device (PCI_VENDOR_ID_NCR, pci_chip_ids[i].pci_device_id, pci_index, &pci_bus, &pci_device_fn); ++pci_index) if (!ncr_pci_init (tpnt, BOARD_GENERIC, pci_chip_ids[i].chip, pci_bus, pci_device_fn, /* no options */ 0)) ++count; } return count;}/* NCR53c810 and NCR53c820 script handling code */#include "53c8xx_d.h"#ifdef A_int_debug_sync#define DEBUG_SYNC_INTR A_int_debug_sync#endifstatic int NCR53c8xx_script_len = sizeof (SCRIPT);static int NCR53c8xx_dsa_len = A_dsa_end + Ent_dsa_zero - Ent_dsa_code_template;/* * Function : static void NCR53c8x0_init_fixup (struct Scsi_Host *host) * * Purpose : copy and fixup the SCSI SCRIPTS(tm) code for this device. * * Inputs : host - pointer to this host adapter's structure * */static void NCR53c8x0_init_fixup (struct Scsi_Host *host) { NCR53c7x0_local_declare(); struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata; unsigned char tmp; int i, ncr_to_memory, memory_to_ncr; u32 base;#ifdef __powerpc__ unsigned long *script_ptr;#endif NCR53c7x0_local_setup(host); /* XXX - NOTE : this code MUST be made endian aware */ /* Copy code into buffer that was allocated at detection time. */ memcpy ((void *) hostdata->script, (void *) SCRIPT, sizeof(SCRIPT)); /* Fixup labels */ for (i = 0; i < PATCHES; ++i) hostdata->script[LABELPATCHES[i]] += virt_to_bus(hostdata->script); /* Fixup addresses of constants that used to be EXTERNAL */ patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_abort, virt_to_bus(&(hostdata->NCR53c7xx_msg_abort))); patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_reject, virt_to_bus(&(hostdata->NCR53c7xx_msg_reject))); patch_abs_32 (hostdata->script, 0, NCR53c7xx_zero, virt_to_bus(&(hostdata->NCR53c7xx_zero))); patch_abs_32 (hostdata->script, 0, NCR53c7xx_sink, virt_to_bus(&(hostdata->NCR53c7xx_sink))); patch_abs_32 (hostdata->script, 0, NOP_insn, virt_to_bus(&(hostdata->NOP_insn))); patch_abs_32 (hostdata->script, 0, schedule, virt_to_bus((void *) hostdata->schedule)); /* Fixup references to external variables: */ for (i = 0; i < EXTERNAL_PATCHES_LEN; ++i) hostdata->script[EXTERNAL_PATCHES[i].offset] += virt_to_bus(EXTERNAL_PATCHES[i].address); /* * Fixup absolutes set at boot-time. * * All non-code absolute variables suffixed with "dsa_" and "int_" * are constants, and need no fixup provided the assembler has done * it for us (I don't know what the "real" NCR assembler does in * this case, my assembler does the right magic). */ patch_abs_rwri_data (hostdata->script, 0, dsa_save_data_pointer, Ent_dsa_code_save_data_pointer - Ent_dsa_zero); patch_abs_rwri_data (hostdata->script, 0, dsa_restore_pointers, Ent_dsa_code_restore_pointers - Ent_dsa_zero); patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect, Ent_dsa_code_check_reselect - Ent_dsa_zero); /* * Just for the hell of it, preserve the settings of * Burst Length and Enable Read Line bits from the DMODE * register. Make sure SCRIPTS start automagically. */ tmp = NCR53c7x0_read8(DMODE_REG_10); tmp &= (DMODE_800_ERL | DMODE_BL_MASK); if (!(hostdata->options & OPTION_MEMORY_MAPPED)) { base = (u32) host->io_port; memory_to_ncr = tmp|DMODE_800_DIOM; ncr_to_memory = tmp|DMODE_800_SIOM; } else { base = virt_to_bus(host->base); memory_to_ncr = ncr_to_memory = tmp; } patch_abs_32 (hostdata->script, 0, addr_scratch, base + SCRATCHA_REG_800); patch_abs_32 (hostdata->script, 0, addr_temp, base + TEMP_REG); /* * I needed some variables in the script to be accessible to * both the NCR chip and the host processor. For these variables, * I made the arbitrary decision to store them directly in the * hostdata structure rather than in the RELATIVE area of the * SCRIPTS. */ patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_memory, tmp); patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_ncr, memory_to_ncr); patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_memory, ncr_to_memory); patch_abs_32 (hostdata->script, 0, msg_buf, virt_to_bus((void *)&(hostdata->msg_buf))); patch_abs_32 (hostdata->script, 0, reconnect_dsa_head, virt_to_bus((void *)&(hostdata->reconnect_dsa_head))); patch_abs_32 (hostdata->script, 0, addr_reconnect_dsa_head, virt_to_bus((void *)&(hostdata->addr_reconnect_dsa_head))); patch_abs_32 (hostdata->script, 0, reselected_identify, virt_to_bus((void *)&(hostdata->reselected_identify)));/* reselected_tag is currently unused */#if 0 patch_abs_32 (hostdata->script, 0, reselected_tag, virt_to_bus((void *)&(hostdata->reselected_tag)));#endif patch_abs_32 (hostdata->script, 0, test_dest, virt_to_bus((void*)&hostdata->test_dest)); patch_abs_32 (hostdata->script, 0, test_src, virt_to_bus(&hostdata->test_source)); patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect, (unsigned char)(Ent_dsa_code_check_reselect - Ent_dsa_zero));/* These are for event logging; the ncr_event enum contains the actual interrupt numbers. */#ifdef A_int_EVENT_SELECT patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT, (u32) EVENT_SELECT);#endif#ifdef A_int_EVENT_DISCONNECT patch_abs_32 (hostdata->script, 0, int_EVENT_DISCONNECT, (u32) EVENT_DISCONNECT);#endif#ifdef A_int_EVENT_RESELECT patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT, (u32) EVENT_RESELECT);#endif#ifdef A_int_EVENT_COMPLETE patch_abs_32 (hostdata->script, 0, int_EVENT_COMPLETE, (u32) EVENT_COMPLETE);#endif#ifdef A_int_EVENT_IDLE patch_abs_32 (hostdata->script, 0, int_EVENT_IDLE, (u32) EVENT_IDLE);#endif#ifdef A_int_EVENT_SELECT_FAILED patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT_FAILED, (u32) EVENT_SELECT_FAILED);#endif#ifdef A_int_EVENT_BEFORE_SELECT patch_abs_32 (hostdata->script, 0, int_EVENT_BEFORE_SELECT, (u32) EVENT_BEFORE_SELECT);#endif#ifdef A_int_EVENT_RESELECT_FAILED patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT_FAILED, (u32) EVENT_RESELECT_FAILED);#endif /* * Make sure the NCR and Linux code agree on the location of * certain fields. */ hostdata->E_accept_message = Ent_accept_message; hostdata->E_command_complete = Ent_command_complete; hostdata->E_cmdout_cmdout = Ent_cmdout_cmdout; hostdata->E_data_transfer = Ent_data_transfer; hostdata->E_debug_break = Ent_debug_break; hostdata->E_dsa_code_template = Ent_dsa_code_template; hostdata->E_dsa_code_template_end = Ent_dsa_code_template_end; hostdata->E_end_data_transfer = Ent_end_data_transfer; hostdata->E_initiator_abort = Ent_initiator_abort; hostdata->E_msg_in = Ent_msg_in; hostdata->E_other_transfer = Ent_other_transfer; hostdata->E_other_in = Ent_other_in; hostdata->E_other_out = Ent_other_out; hostdata->E_reject_message = Ent_reject_message; hostdata->E_respond_message = Ent_respond_message; hostdata->E_select = Ent_select; hostdata->E_select_msgout = Ent_select_msgout; hostdata->E_target_abort = Ent_target_abort;#ifdef Ent_test_0 hostdata->E_test_0 = Ent_test_0;#endif hostdata->E_test_1 = Ent_test_1; hostdata->E_test_2 = Ent_test_2;#ifdef Ent_test_3 hostdata->E_test_3 = Ent_test_3;#endif hostdata->E_wait_reselect = Ent_wait_reselect; hostdata->E_dsa_code_begin = Ent_dsa_code_begin; hostdata->dsa_cmdout = A_dsa_cmdout; hostdata->dsa_cmnd = A_dsa_cmnd; hostdata->dsa_datain = A_dsa_datain; hostdata->dsa_dataout = A_dsa_dataout; hostdata->dsa_end = A_dsa_end; hostdata->dsa_msgin = A_dsa_msgin; hostdata->dsa_msgout = A_dsa_msgout; hostdata->dsa_msgout_other = A_dsa_msgout_other; hostdata->dsa_next = A_dsa_next; hostdata->dsa_select = A_dsa_select; hostdata->dsa_start = Ent_dsa_code_template - Ent_dsa_zero; hostdata->dsa_status = A_dsa_status; hostdata->dsa_jump_dest = Ent_dsa_code_fix_jump - Ent_dsa_zero + 8 /* destination operand */; /* sanity check */ if (A_dsa_fields_start != Ent_dsa_code_template_end - Ent_dsa_zero) printk("scsi%d : NCR dsa_fields start is %d not %d\n", host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end - Ent_dsa_zero);#ifdef __powerpc__/* The PowerPC is Big Endian - adjust script appropriately */ script_ptr = hostdata->script; for (i = 0; i < sizeof(SCRIPT); i += sizeof(long)) { *script_ptr++ = le32_to_cpu(*script_ptr); }#endif printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no, virt_to_bus(hostdata->script), hostdata->script);}/* * Function : static int NCR53c8xx_run_tests (struct Scsi_Host *host) * * Purpose : run various verification tests on the NCR chip, * including interrupt generation, and proper bus mastering * operation. * * Inputs : host - a properly initialized Scsi_Host structure * * Preconditions : the NCR chip must be in a halted state. * * Returns : 0 if all tests were successful, -1 on error. * */static int NCR53c8xx_run_tests (struct Scsi_Host *host) { NCR53c7x0_local_declare(); struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata; unsigned long timeout; u32 start; int failed, i; unsigned long flags; NCR53c7x0_local_setup(host); /* The NCR chip _must_ be idle to run the test scripts */ save_flags(flags); cli(); if (!hostdata->idle) { printk ("scsi%d : chip not idle, aborting tests\n", host->host_no); restore_flags(flags); return -1; } /* * Check for functional interrupts, this could work as an * autoprobe routine. */ if ((hostdata->options & OPTION_DEBUG_TEST1) && hostdata->state != STATE_DISABLED) { hostdata->idle = 0; hostdata->test_running = 1; hostdata->test_completed = -1; hostdata->test_dest = 0; hostdata->test_source = 0xdeadbeef; start = virt_to_bus (hostdata->script) + hostdata->E_test_1; hostdata->state = STATE_RUNNING; printk ("scsi%d : test 1", host->host_no); NCR53c7x0_write32 (DSP_REG, start); printk (" started\n"); restore_flags(flags); /* * This is currently a .5 second timeout, since (in theory) no slow * board will take that long. In practice, we've seen one * pentium which occasionally fails with this, but works with * 10 times as much? */ timeout = jiffies + 5 * HZ / 10; while ((hostdata->test_completed == -1) && jiffies < timeout) barrier(); failed = 1; if (hostdata->test_completed == -1) printk ("scsi%d : driver test 1 timed out%s\n",host->host_no , (hostdata->test_dest == 0xdeadbeef) ? " due to lost interrupt.\n" " Please verify that the correct IRQ is being used for your board,\n" " and that the motherboard IRQ jumpering matches the PCI setup on\n" " PCI systems.\n" " If you are using a NCR53c810 board in a PCI system, you should\n" " also verify that the board is jumpered to use PCI INTA, since\n" " most PCI motherboards lack support for INTB, INTC, and INTD.\n" : ""); else if (hostdata->test_completed != 1) printk ("scsi%d : test 1 bad interrupt value (%d)\n", host->host_no, hostdata->test_completed); else failed = (hostdata->test_dest != 0xdeadbeef); if (hostdata->test_dest != 0xdeadbeef) { printk ("scsi%d : driver test 1 read 0x%x instead of 0xdeadbeef indicating a\n" " probable cache invalidation problem. Please configure caching\n" " as write-through or disabled\n", host->host_no, hostdata->test_dest); } if (failed) { printk ("scsi%d : DSP = 0x%p (script at 0x%p, start at 0x%x)\n", host->host_no, bus_to_virt(NCR53c7x0_read32(DSP_REG)), hostdata->script, start); printk ("scsi%d : DSPS =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -