📄 adwlib.c
字号:
/* * Clear the rest of LRAM. */ for (; addr < ADW_CONDOR_MEMSIZE/2; addr++) adw_outw(adw, ADW_RAM_DATA, 0); /* * Verify the microcode checksum. */ checksum = 0; adw_outw(adw, ADW_RAM_ADDR, 0); for (addr = 0; addr < adw_mcode_size/2; addr++) checksum += adw_inw(adw, ADW_RAM_DATA); if (checksum != adw_mcode_chksum) { printf("%s: Firmware load failed!\n", adw_name(adw)); return (-1); } /* * Restore the RISC memory BIOS region. */ for (addr = 0; addr < ADW_MC_BIOSLEN; addr++) adw_lram_write_8(adw, addr + ADW_MC_BIOSLEN, biosmem[addr]); /* * Calculate and write the microcode code checksum to * the microcode code checksum location. */ addr = adw_lram_read_16(adw, ADW_MC_CODE_BEGIN_ADDR) / 2; end_addr = adw_lram_read_16(adw, ADW_MC_CODE_END_ADDR) / 2; checksum = 0; for (; addr < end_addr; addr++) checksum += mcodebuf[addr]; adw_lram_write_16(adw, ADW_MC_CODE_CHK_SUM, checksum); /* * Initialize microcode operating variables */ adw_lram_write_16(adw, ADW_MC_ADAPTER_SCSI_ID, adw->initiator_id); /* * Leave WDTR and SDTR negotiation disabled until the XPT has * informed us of device capabilities, but do set the ultra mask * in case we receive an SDTR request from the target before we * negotiate. We turn on tagged queuing at the microcode level * for all devices, and modulate this on a per command basis. */ adw_lram_write_16(adw, ADW_MC_ULTRA_ABLE, adw->user_ultra); adw_lram_write_16(adw, ADW_MC_DISC_ENABLE, adw->user_discenb); adw_lram_write_16(adw, ADW_MC_TAGQNG_ABLE, ~0); /* * Set SCSI_CFG0 Microcode Default Value. * * The microcode will set the SCSI_CFG0 register using this value * after it is started. */ adw_lram_write_16(adw, ADW_MC_DEFAULT_SCSI_CFG0, ADW_SCSI_CFG0_PARITY_EN|ADW_SCSI_CFG0_SEL_TMO_LONG| ADW_SCSI_CFG0_OUR_ID_EN|adw->initiator_id); /* * Determine SCSI_CFG1 Microcode Default Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below. */ scsicfg1 = adw_inw(adw, ADW_SCSI_CFG1); /* * If all three connectors are in use, return an error. */ if ((scsicfg1 & ADW_SCSI_CFG1_ILLEGAL_CABLE_CONF_A_MASK) == 0 || (scsicfg1 & ADW_SCSI_CFG1_ILLEGAL_CABLE_CONF_B_MASK) == 0) { printf("%s: Illegal Cable Config!\n", adw_name(adw)); printf("%s: Only Two Ports may be used at a time!\n", adw_name(adw)); return (-1); } /* * If the internal narrow cable is reversed all of the SCSI_CTRL * register signals will be set. Check for and return an error if * this condition is found. */ if ((adw_inw(adw, ADW_SCSI_CTRL) & 0x3F07) == 0x3F07) { printf("%s: Illegal Cable Config!\n", adw_name(adw)); printf("%s: Internal cable is reversed!\n", adw_name(adw)); return (-1); } /* * If this is a differential board and a single-ended device * is attached to one of the connectors, return an error. */ if ((scsicfg1 & ADW_SCSI_CFG1_DIFF_MODE) != 0 && (scsicfg1 & ADW_SCSI_CFG1_DIFF_SENSE) == 0) { printf("%s: A Single Ended Device is attached to our " "differential bus!\n", adw_name(adw)); return (-1); } /* * Perform automatic termination control if desired. */ if (term_scsicfg1 == 0) { switch(scsicfg1 & ADW_SCSI_CFG1_CABLE_DETECT) { case (ADW_SCSI_CFG1_INT16_MASK|ADW_SCSI_CFG1_INT8_MASK): case (ADW_SCSI_CFG1_INT16_MASK| ADW_SCSI_CFG1_INT8_MASK|ADW_SCSI_CFG1_EXT8_MASK): case (ADW_SCSI_CFG1_INT16_MASK| ADW_SCSI_CFG1_INT8_MASK|ADW_SCSI_CFG1_EXT16_MASK): case (ADW_SCSI_CFG1_INT16_MASK| ADW_SCSI_CFG1_EXT8_MASK|ADW_SCSI_CFG1_EXT16_MASK): case (ADW_SCSI_CFG1_INT8_MASK| ADW_SCSI_CFG1_EXT8_MASK|ADW_SCSI_CFG1_EXT16_MASK): case (ADW_SCSI_CFG1_INT16_MASK|ADW_SCSI_CFG1_INT8_MASK| ADW_SCSI_CFG1_EXT8_MASK|ADW_SCSI_CFG1_EXT16_MASK): /* Two out of three cables missing. Both on. */ term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L | ADW_SCSI_CFG1_TERM_CTL_H; break; case (ADW_SCSI_CFG1_INT16_MASK): case (ADW_SCSI_CFG1_INT16_MASK|ADW_SCSI_CFG1_EXT8_MASK): case (ADW_SCSI_CFG1_INT16_MASK|ADW_SCSI_CFG1_EXT16_MASK): case (ADW_SCSI_CFG1_INT8_MASK|ADW_SCSI_CFG1_EXT16_MASK): case (ADW_SCSI_CFG1_EXT8_MASK|ADW_SCSI_CFG1_EXT16_MASK): /* No two 16bit cables present. High on. */ term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H; break; case (ADW_SCSI_CFG1_INT8_MASK): case (ADW_SCSI_CFG1_INT8_MASK|ADW_SCSI_CFG1_EXT8_MASK): /* Wide -> Wide or Narrow -> Wide. Both off */ break; } } /* Tell the user about our decission */ switch (term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK) { case ADW_SCSI_CFG1_TERM_CTL_MASK: printf("High & Low Termination Enabled, "); break; case ADW_SCSI_CFG1_TERM_CTL_H: printf("High Termination Enabled, "); break; case ADW_SCSI_CFG1_TERM_CTL_L: printf("Low Termination Enabled, "); break; default: break; } /* * Invert the TERM_CTL_H and TERM_CTL_L bits and then * set 'scsicfg1'. The TERM_POL bit does not need to be * referenced, because the hardware internally inverts * the Termination High and Low bits if TERM_POL is set. */ term_scsicfg1 = ~term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK; scsicfg1 &= ~ADW_SCSI_CFG1_TERM_CTL_MASK; scsicfg1 |= term_scsicfg1 | ADW_SCSI_CFG1_TERM_CTL_MANUAL; /* * Set SCSI_CFG1 Microcode Default Value * * Set filter value and possibly modified termination control * bits in the Microcode SCSI_CFG1 Register Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below. */ adw_lram_write_16(adw, ADW_MC_DEFAULT_SCSI_CFG1, scsicfg1 | ADW_SCSI_CFG1_FLTR_11_TO_20NS); /* * Only accept selections on our initiator target id. * This may change in target mode scenarios... */ adw_lram_write_16(adw, ADW_MC_DEFAULT_SEL_MASK, (0x01 << adw->initiator_id)); /* * Link all the RISC Queue Lists together in a doubly-linked * NULL terminated list. * * Skip the NULL (0) queue which is not used. */ for (i = 1, addr = ADW_MC_RISC_Q_LIST_BASE + ADW_MC_RISC_Q_LIST_SIZE; i < ADW_MC_RISC_Q_TOTAL_CNT; i++, addr += ADW_MC_RISC_Q_LIST_SIZE) { /* * Set the current RISC Queue List's * RQL_FWD and RQL_BWD pointers in a * one word write and set the state * (RQL_STATE) to free. */ adw_lram_write_16(adw, addr, ((i + 1) | ((i - 1) << 8))); adw_lram_write_8(adw, addr + RQL_STATE, ADW_MC_QS_FREE); } /* * Set the Host and RISC Queue List pointers. * * Both sets of pointers are initialized with the same values: * ADW_MC_RISC_Q_FIRST(0x01) and ADW_MC_RISC_Q_LAST (0xFF). */ adw_lram_write_8(adw, ADW_MC_HOST_NEXT_READY, ADW_MC_RISC_Q_FIRST); adw_lram_write_8(adw, ADW_MC_HOST_NEXT_DONE, ADW_MC_RISC_Q_LAST); adw_lram_write_8(adw, ADW_MC_RISC_NEXT_READY, ADW_MC_RISC_Q_FIRST); adw_lram_write_8(adw, ADW_MC_RISC_NEXT_DONE, ADW_MC_RISC_Q_LAST); /* * Set up the last RISC Queue List (255) with a NULL forward pointer. */ adw_lram_write_16(adw, addr, (ADW_MC_NULL_Q + ((i - 1) << 8))); adw_lram_write_8(adw, addr + RQL_STATE, ADW_MC_QS_FREE); adw_outb(adw, ADW_INTR_ENABLES, ADW_INTR_ENABLE_HOST_INTR|ADW_INTR_ENABLE_GLOBAL_INTR); adw_outw(adw, ADW_PC, adw_lram_read_16(adw, ADW_MC_CODE_BEGIN_ADDR)); return (0);}/* * Send an idle command to the chip and optionally wait for completion. */voidadw_idle_cmd_send(struct adw_softc *adw, adw_idle_cmd_t cmd, u_int parameter){ int s; adw->idle_command_cmp = 0; s = splcam(); if (adw->idle_cmd != ADW_IDLE_CMD_COMPLETED) printf("%s: Warning! Overlapped Idle Commands Attempted\n", adw_name(adw)); adw->idle_cmd = cmd; adw->idle_cmd_param = parameter; /* * Write the idle command value after the idle command parameter * has been written to avoid a race condition. If the order is not * followed, the microcode may process the idle command before the * parameters have been written to LRAM. */ adw_lram_write_16(adw, ADW_MC_IDLE_PARA_STAT, parameter); adw_lram_write_16(adw, ADW_MC_IDLE_CMD, cmd); splx(s);}/* Wait for an idle command to complete */adw_idle_cmd_status_tadw_idle_cmd_wait(struct adw_softc *adw){ u_int timeout; adw_idle_cmd_status_t status; int s; /* Wait for up to 10 seconds for the command to complete */ timeout = 10000; while (--timeout) { if (adw->idle_command_cmp != 0) break; DELAY(1000); } if (timeout == 0) panic("%s: Idle Command Timed Out!\n", adw_name(adw)); s = splcam(); status = adw_lram_read_16(adw, ADW_MC_IDLE_PARA_STAT); splx(s); return (status);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -