📄 53c7xx.c
字号:
so we only need one here, and don't need to allocate NCR53c7x0_cmd structures for each target until we are no longer in scan_scsis and kmalloc() has become functional (memory_init() happens after all device driver initialization). */ size = sizeof(struct NCR53c7x0_hostdata) + script_len + /* Note that alignment will be guaranteed, since we put the command allocated at probe time after the fixed-up SCSI script, which consists of 32 bit words, aligned on a 32 bit boundary. But on a 64bit machine we need 8 byte alignment for hostdata->free, so we add in another 4 bytes to take care of potential misalignment */ (sizeof(void *) - sizeof(u32)) + max_cmd_size + schedule_size; page = __get_free_pages(GFP_ATOMIC,1); if(page==0) { printk(KERN_ERR "53c7xx: out of memory.\n"); return -ENOMEM; }#ifdef FORCE_DSA_ALIGNMENT /* * 53c710 rev.0 doesn't have an add-with-carry instruction. * Ensure we allocate enough memory to force DSA alignment. */ size += 256;#endif /* Size should be < 8K, so we can fit it in two pages. */ if (size > 8192) panic("53c7xx: hostdata > 8K"); instance = scsi_register (tpnt, 4); if (!instance) { free_page(page); return -1; } instance->hostdata[0] = page; memset((void *)instance->hostdata[0], 0, 8192); cache_push(virt_to_phys((void *)(instance->hostdata[0])), 8192); cache_clear(virt_to_phys((void *)(instance->hostdata[0])), 8192); kernel_set_cachemode(instance->hostdata[0], 8192, IOMAP_NOCACHE_SER); /* FIXME : if we ever support an ISA NCR53c7xx based board, we need to check if the chip is running in a 16 bit mode, and if so unregister it if it is past the 16M (0x1000000) mark */ hostdata = (struct NCR53c7x0_hostdata *)instance->hostdata[0]; hostdata->size = size; hostdata->script_count = script_len / sizeof(u32); hostdata->board = board; hostdata->chip = chip; /* * Being memory mapped is more desirable, since * * - Memory accesses may be faster. * * - The destination and source address spaces are the same for * all instructions, meaning we don't have to twiddle dmode or * any other registers. * * So, we try for memory mapped, and if we don't get it, * we go for port mapped, and that failing we tell the user * it can't work. */ if (base) { instance->base = (unsigned char *) (unsigned long) base; /* Check for forced I/O mapping */ if (!(options & OPTION_IO_MAPPED)) { options |= OPTION_MEMORY_MAPPED; ok = 1; } } else { options &= ~OPTION_MEMORY_MAPPED; } if (io_port) { instance->io_port = io_port; options |= OPTION_IO_MAPPED; ok = 1; } else { options &= ~OPTION_IO_MAPPED; } if (!ok) { printk ("scsi%d : not initializing, no I/O or memory mapping known \n", instance->host_no); scsi_unregister (instance); return -1; } instance->irq = irq; instance->dma_channel = dma; hostdata->options = options; hostdata->dsa_len = dsa_len; hostdata->max_cmd_size = max_cmd_size; hostdata->num_cmds = 1; hostdata->scsi_clock = clock; /* Initialize single command */ tmp = (hostdata->script + hostdata->script_count);#ifdef FORCE_DSA_ALIGNMENT { void *t = ROUNDUP(tmp, void *); if (((u32)t & 0xff) > CmdPageStart) t = (void *)((u32)t + 255); t = (void *)(((u32)t & ~0xff) + CmdPageStart); hostdata->free = t;#if 0 printk ("scsi: Registered size increased by 256 to %d\n", size); printk ("scsi: CmdPageStart = 0x%02x\n", CmdPageStart); printk ("scsi: tmp = 0x%08x, hostdata->free set to 0x%08x\n", (u32)tmp, (u32)t);#endif }#else hostdata->free = ROUNDUP(tmp, void *);#endif hostdata->free->real = tmp; hostdata->free->size = max_cmd_size; hostdata->free->free = NULL; hostdata->free->next = NULL; hostdata->extra_allocate = 0; /* Allocate command start code space */ hostdata->schedule = (chip == 700 || chip == 70066) ? NULL : (u32 *) ((char *)hostdata->free + max_cmd_size);/* * For diagnostic purposes, we don't really care how fast things blaze. * For profiling, we want to access the 800ns resolution system clock, * using a 'C' call on the host processor. * * Therefore, there's no need for the NCR chip to directly manipulate * this data, and we should put it wherever is most convenient for * Linux. */ if (track_events) hostdata->events = (struct NCR53c7x0_event *) (track_events ? vmalloc (sizeof (struct NCR53c7x0_event) * track_events) : NULL); else hostdata->events = NULL; if (hostdata->events) { memset ((void *) hostdata->events, 0, sizeof(struct NCR53c7x0_event) * track_events); hostdata->event_size = track_events; hostdata->event_index = 0; } else hostdata->event_size = 0; return NCR53c7x0_init(instance);}/* * Function : static void NCR53c7x0_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 NCR53c7x0_init_fixup (struct Scsi_Host *host) { NCR53c7x0_local_declare(); struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; unsigned char tmp; int i, ncr_to_memory, memory_to_ncr; u32 base; 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. */#if defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) /* We know better what we want than 16xBug does! */ tmp = DMODE_10_BL_8 | DMODE_10_FC2;#else tmp = NCR53c7x0_read8(DMODE_REG_10); tmp &= (DMODE_BL_MASK | DMODE_10_FC2 | DMODE_10_FC1 | DMODE_710_PD | DMODE_710_UO);#endif 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; } /* SCRATCHB_REG_10 == SCRATCHA_REG_800, as it happens */ patch_abs_32 (hostdata->script, 0, addr_scratch, base + SCRATCHA_REG_800); patch_abs_32 (hostdata->script, 0, addr_temp, base + TEMP_REG); patch_abs_32 (hostdata->script, 0, addr_dsa, base + DSA_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_32 (hostdata->script, 0, saved_dsa, virt_to_bus(&hostdata->saved2_dsa)); patch_abs_32 (hostdata->script, 0, emulfly, virt_to_bus(&hostdata->emulated_intfly)); 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); 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 NCR53c7xx_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. * */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -