📄 53c7xx.c
字号:
static int NCR53c7xx_run_tests (struct Scsi_Host *host) { NCR53c7x0_local_declare(); struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; 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); if (hostdata->options & OPTION_DEBUG_TRACE) NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM | DCNTL_STD); 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 occassionally 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" : ""); 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 = 0x%x\n", host->host_no, NCR53c7x0_read32(DSPS_REG)); restore_flags(flags); return -1; } hostdata->test_running = 0; } if ((hostdata->options & OPTION_DEBUG_TEST2) && hostdata->state != STATE_DISABLED) { u32 dsa[48]; unsigned char identify = IDENTIFY(0, 0); unsigned char cmd[6]; unsigned char data[36]; unsigned char status = 0xff; unsigned char msg = 0xff; cmd[0] = INQUIRY; cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0; cmd[4] = sizeof(data); dsa[2] = 1; dsa[3] = virt_to_bus(&identify); dsa[4] = 6; dsa[5] = virt_to_bus(&cmd); dsa[6] = sizeof(data); dsa[7] = virt_to_bus(&data); dsa[8] = 1; dsa[9] = virt_to_bus(&status); dsa[10] = 1; dsa[11] = virt_to_bus(&msg); for (i = 0; i < 6; ++i) {#ifdef VALID_IDS if (!hostdata->valid_ids[i]) continue;#endif cli(); if (!hostdata->idle) { printk ("scsi%d : chip not idle, aborting tests\n", host->host_no); restore_flags(flags); return -1; } /* 710: bit mapped scsi ID, async */ dsa[0] = (1 << i) << 16; hostdata->idle = 0; hostdata->test_running = 2; hostdata->test_completed = -1; start = virt_to_bus(hostdata->script) + hostdata->E_test_2; hostdata->state = STATE_RUNNING; NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa)); NCR53c7x0_write32 (DSP_REG, start); if (hostdata->options & OPTION_DEBUG_TRACE) NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM | DCNTL_STD); restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ while ((hostdata->test_completed == -1) && jiffies < timeout) barrier(); NCR53c7x0_write32 (DSA_REG, 0); if (hostdata->test_completed == 2) { data[35] = 0; printk ("scsi%d : test 2 INQUIRY to target %d, lun 0 : %s\n", host->host_no, i, data + 8); printk ("scsi%d : status ", host->host_no); print_status (status); printk ("\nscsi%d : message ", host->host_no); print_msg (&msg); printk ("\n"); } else if (hostdata->test_completed == 3) { printk("scsi%d : test 2 no connection with target %d\n", host->host_no, i); if (!hostdata->idle) { printk("scsi%d : not idle\n", host->host_no); restore_flags(flags); return -1; } } else if (hostdata->test_completed == -1) { printk ("scsi%d : test 2 timed out\n", host->host_no); restore_flags(flags); return -1; } hostdata->test_running = 0; } } restore_flags(flags); return 0;}/* * Function : static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) * * Purpose : copy the NCR53c8xx dsa structure into cmd's dsa buffer, * performing all necessary relocation. * * Inputs : cmd, a NCR53c7x0_cmd structure with a dsa area large * enough to hold the NCR53c8xx dsa. */static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) { Scsi_Cmnd *c = cmd->cmd; struct Scsi_Host *host = c->host; struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; int i; memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4), hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template); /* * Note : within the NCR 'C' code, dsa points to the _start_ * of the DSA structure, and _not_ the offset of dsa_zero within * that structure used to facilitate shorter signed offsets * for the 8 bit ALU. * * The implications of this are that * * - 32 bit A_dsa_* absolute values require an additional * dsa_zero added to their value to be correct, since they are * relative to dsa_zero which is in essentially a separate * space from the code symbols. * * - All other symbols require no special treatment. */ patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_lun, c->lun); patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_addr_next, virt_to_bus(&cmd->dsa_next_addr)); patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_next, virt_to_bus(cmd->dsa) + Ent_dsa_zero - Ent_dsa_code_template + A_dsa_next); patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->target].script)); patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->target].sscf_710)); patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_target, 1 << c->target); /* XXX - new pointer stuff */ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_addr_saved_pointer, virt_to_bus(&cmd->saved_data_pointer)); patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_addr_saved_residual, virt_to_bus(&cmd->saved_residual)); patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_addr_residual, virt_to_bus(&cmd->residual)); /* XXX - new start stuff */ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));}/* * Function : run_process_issue_queue (void) * * Purpose : insure that the coroutine is running and will process our * request. process_issue_queue_running is checked/set here (in an * inline function) rather than in process_issue_queue itself to reduce * the chances of stack overflow. * */static volatile int process_issue_queue_running = 0;static __inline__ void run_process_issue_queue(void) { unsigned long flags; save_flags (flags); cli(); if (!process_issue_queue_running) { process_issue_queue_running = 1; process_issue_queue(flags); /* * process_issue_queue_running is cleared in process_issue_queue * once it can't do more work, and process_issue_queue exits with * interrupts disabled. */ } restore_flags (flags);}/* * Function : static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int * result) * * Purpose : mark SCSI command as finished, OR'ing the host portion * of the result word into the result field of the corresponding * Scsi_Cmnd structure, and removing it from the internal queues. * * Inputs : cmd - command, result - entire result field * * Preconditions : the NCR chip should be in a halted state when * abnormal_finished is run, since it modifies structures which * the NCR expects to have exclusive access to. */static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) { Scsi_Cmnd *c = cmd->cmd; struct Scsi_Host *host = c->host; struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; unsigned long flags; int left, found; volatile struct NCR53c7x0_cmd * linux_search; volatile struct NCR53c7x0_cmd * volatile *linux_prev; volatile u32 *ncr_prev, *ncrcurrent, ncr_search;#if 0 printk ("scsi%d: abnormal finished\n", host->host_no);#endif save_flags(flags); cli(); found = 0; /* * Traverse the NCR issue array until we find a match or run out * of instructions. Instructions in the NCR issue array are * either JUMP or NOP instructions, which are 2 words in length. */ for (found = 0, left = host->can_queue, ncrcurrent = hostdata->schedule; left > 0; --left, ncrcurrent += 2) { if (issue_to_cmd (host, hostdata, (u32 *) ncrcurrent) == cmd) { ncrcurrent[0] = hostdata->NOP_insn; ncrcurrent[1] = 0xdeadbeef; ++found; break; } } /* * Traverse the NCR reconnect list of DSA structures until we find * a pointer to this dsa or have found too many command structures. * We let prev point at the next field of the previous element or * head of the list, so we don't do anything different for removing * the head element. */ for (left = host->can_queue, ncr_search = hostdata->reconnect_dsa_head, ncr_prev = &hostdata->reconnect_dsa_head; left >= 0 && ncr_search && ((char*)bus_to_virt(ncr_search) + hostdata->dsa_start) != (char *) cmd->dsa; ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) + hostdata->dsa_next), ncr_search = *ncr_prev, --left); if (left < 0) printk("scsi%d: loop detected in ncr reconncect list\n", host->host_no); else if (ncr_search) { if (found) printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n", host->host_no, c->pid); else { volatile u32 * next = (u32 *) ((char *)bus_to_virt(ncr_search) + hostdata->dsa_next); *ncr_prev = *next;/* If we're at the tail end of the issue queue, update that pointer too. */ found = 1; } } /* * Traverse the host running list until we find this command or discover * we have too many elements, pointing linux_prev at the next field of the * linux_previous element or head of the list, search at this element. */ for (left = host->can_queue, linux_search = hostdata->running_list, linux_prev = &hostdata->running_list; left >= 0 && linux_search && linux_search != cmd; linux_prev = &(linux_search->next), linux_search = linux_search->next, --left); if (left < 0) printk ("scsi%d: loop detected in host running list for scsi pid %ld\n", host->host_no, c->pid); else if (linux_search) { *linux_prev = linux_search->next; --hostdata->busy[c->target][c->lun]; } /* Return the NCR command structure to the free list */ cmd->next = hostdata->free; hostdata->free = cmd; c->host_scribble = NULL; /* And return */ c->result = result; c->scsi_done(c); restore_flags(flags); run_process_issue_queue();}/* * Function : static void intr_break (struct Scsi_Host *host, * struct NCR53c7x0_cmd *cmd) * * Purpose : Handler for breakpoint interrupts from a SCSI script * * Inputs : host - pointer to this host adapter's structure, * cmd - poi
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -