advlib.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,047 行 · 第 1/4 页
C
2,047 行
/* * Low level routines for the Advanced Systems Inc. SCSI controllers chips * * Copyright (c) 1996-1997 Justin Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: advlib.c,v 1.10.2.2 1999/05/07 00:43:21 ken Exp $ *//* * Ported from: * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters * * Copyright (c) 1995-1996 Advanced System Products, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that redistributions of source * code retain the above copyright notice and this comment without * modification. */#include <sys/param.h>#include <sys/kernel.h>#include <sys/systm.h>#include <machine/bus_pio.h>#include <machine/bus.h>#include <machine/clock.h>#include <cam/cam.h>#include <cam/cam_ccb.h>#include <cam/cam_sim.h>#include <cam/cam_xpt_sim.h>#include <cam/scsi/scsi_all.h>#include <cam/scsi/scsi_message.h>#include <cam/scsi/scsi_da.h>#include <cam/scsi/scsi_cd.h>#include <vm/vm.h>#include <vm/vm_param.h>#include <vm/pmap.h>#include <dev/advansys/advansys.h>#include <dev/advansys/advmcode.h>struct adv_quirk_entry { struct scsi_inquiry_pattern inq_pat; u_int8_t quirks;#define ADV_QUIRK_FIX_ASYN_XFER_ALWAYS 0x01#define ADV_QUIRK_FIX_ASYN_XFER 0x02};static struct adv_quirk_entry adv_quirk_table[] ={ { { T_CDROM, SIP_MEDIA_REMOVABLE, "HP", "*", "*" }, ADV_QUIRK_FIX_ASYN_XFER_ALWAYS|ADV_QUIRK_FIX_ASYN_XFER }, { { T_CDROM, SIP_MEDIA_REMOVABLE, "NEC", "CD-ROM DRIVE", "*" }, 0 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", " TDC 36", "*" }, 0 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", "*", "*" }, 0 }, { { T_PROCESSOR, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, "*", "*", "*" }, 0 }, { { T_SCANNER, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, "*", "*", "*" }, 0 }, { /* Default quirk entry */ { T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, /*vendor*/"*", /*product*/"*", /*revision*/"*" }, ADV_QUIRK_FIX_ASYN_XFER, }};/* * Allowable periods in ns */u_int8_t adv_sdtr_period_tbl[] ={ 25, 30, 35, 40, 50, 60, 70, 85};u_int8_t adv_sdtr_period_tbl_ultra[] ={ 12, 19, 25, 32, 38, 44, 50, 57, 63, 69, 75, 82, 88, 94, 100, 107};struct ext_msg { u_int8_t msg_type; u_int8_t msg_len; u_int8_t msg_req; union { struct { u_int8_t sdtr_xfer_period; u_int8_t sdtr_req_ack_offset; } sdtr; struct { u_int8_t wdtr_width; } wdtr; struct { u_int8_t mdp[4]; } mdp; } u_ext_msg; u_int8_t res;};#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset#define wdtr_width u_ext_msg.wdtr.wdtr_width#define mdp_b3 u_ext_msg.mdp_b3#define mdp_b2 u_ext_msg.mdp_b2#define mdp_b1 u_ext_msg.mdp_b1#define mdp_b0 u_ext_msg.mdp_b0/* * Some of the early PCI adapters have problems with * async transfers. Instead use an offset of 1. */#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41/* LRAM routines */static void adv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, u_int16_t *buffer, int count);static void adv_write_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, u_int16_t *buffer, int count);static void adv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr, u_int16_t set_value, int count);static u_int32_t adv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, int count);static int adv_write_and_verify_lram_16(struct adv_softc *adv, u_int16_t addr, u_int16_t value);static u_int32_t adv_read_lram_32(struct adv_softc *adv, u_int16_t addr);static void adv_write_lram_32(struct adv_softc *adv, u_int16_t addr, u_int32_t value);static void adv_write_lram_32_multi(struct adv_softc *adv, u_int16_t s_addr, u_int32_t *buffer, int count);/* EEPROM routines */static u_int16_t adv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr);static u_int16_t adv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, u_int16_t value);static int adv_write_eeprom_cmd_reg(struct adv_softc *adv, u_int8_t cmd_reg);static int adv_set_eeprom_config_once(struct adv_softc *adv, struct adv_eeprom_config *eeconfig);/* Initialization */static u_int32_t adv_load_microcode(struct adv_softc *adv, u_int16_t s_addr, u_int16_t *mcode_buf, u_int16_t mcode_size);static void adv_reinit_lram(struct adv_softc *adv);static void adv_init_lram(struct adv_softc *adv);static int adv_init_microcode_var(struct adv_softc *adv);static void adv_init_qlink_var(struct adv_softc *adv);/* Interrupts */static void adv_disable_interrupt(struct adv_softc *adv);static void adv_enable_interrupt(struct adv_softc *adv);static void adv_toggle_irq_act(struct adv_softc *adv);/* Chip Control */static int adv_stop_chip(struct adv_softc *adv);static int adv_host_req_chip_halt(struct adv_softc *adv);static void adv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code);#if UNUSEDstatic u_int8_t adv_get_chip_scsi_ctrl(struct adv_softc *adv);#endif/* Queue handling and execution */static __inline int adv_sgcount_to_qcount(int sgcount);static __inline intadv_sgcount_to_qcount(int sgcount){ int n_sg_list_qs; n_sg_list_qs = ((sgcount - 1) / ADV_SG_LIST_PER_Q); if (((sgcount - 1) % ADV_SG_LIST_PER_Q) != 0) n_sg_list_qs++; return (n_sg_list_qs + 1);}static void adv_get_q_info(struct adv_softc *adv, u_int16_t s_addr, u_int16_t *inbuf, int words);static u_int adv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs);static u_int8_t adv_alloc_free_queues(struct adv_softc *adv, u_int8_t free_q_head, u_int8_t n_free_q);static u_int8_t adv_alloc_free_queue(struct adv_softc *adv, u_int8_t free_q_head);static int adv_send_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, u_int8_t n_q_required);static void adv_put_ready_sg_list_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, u_int q_no);static void adv_put_ready_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, u_int q_no);static void adv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr, u_int16_t *buffer, int words);/* Messages */static void adv_handle_extmsg_in(struct adv_softc *adv, u_int16_t halt_q_addr, u_int8_t q_cntl, target_bit_vector target_id, int tid);static void adv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period, u_int8_t sdtr_offset);static void adv_set_sdtr_reg_at_id(struct adv_softc *adv, int id, u_int8_t sdtr_data);/* Exported functions first */voidadvasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg){ struct adv_softc *adv; adv = (struct adv_softc *)callback_arg; switch (code) { case AC_FOUND_DEVICE: { struct ccb_getdev *cgd; target_bit_vector target_mask; int num_entries; caddr_t match; struct adv_quirk_entry *entry; struct adv_target_transinfo* tinfo; cgd = (struct ccb_getdev *)arg; target_mask = ADV_TID_TO_TARGET_MASK(cgd->ccb_h.target_id); num_entries = sizeof(adv_quirk_table)/sizeof(*adv_quirk_table); match = cam_quirkmatch((caddr_t)&cgd->inq_data, (caddr_t)adv_quirk_table, num_entries, sizeof(*adv_quirk_table), scsi_inquiry_match); if (match == NULL) panic("advasync: device didn't match wildcard entry!!"); entry = (struct adv_quirk_entry *)match; if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) { if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER_ALWAYS)!=0) adv->fix_asyn_xfer_always |= target_mask; else adv->fix_asyn_xfer_always &= ~target_mask; /* * We start out life with all bits set and clear them * after we've determined that the fix isn't necessary. * It may well be that we've already cleared a target * before the full inquiry session completes, so don't * gratuitously set a target bit even if it has this * quirk. But, if the quirk exonerates a device, clear * the bit now. */ if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER) == 0) adv->fix_asyn_xfer &= ~target_mask; } /* * Reset our sync settings now that we've determined * what quirks are in effect for the device. */ tinfo = &adv->tinfo[cgd->ccb_h.target_id]; adv_set_syncrate(adv, cgd->ccb_h.path, cgd->ccb_h.target_id, tinfo->current.period, tinfo->current.offset, ADV_TRANS_CUR); break; } case AC_LOST_DEVICE: { u_int target_mask; if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) { target_mask = 0x01 << xpt_path_target_id(path); adv->fix_asyn_xfer |= target_mask; } /* * Revert to async transfers * for the next device. */ adv_set_syncrate(adv, /*path*/NULL, xpt_path_target_id(path), /*period*/0, /*offset*/0, ADV_TRANS_GOAL|ADV_TRANS_CUR); } default: break; }}voidadv_set_bank(struct adv_softc *adv, u_int8_t bank){ u_int8_t control; /* * Start out with the bank reset to 0 */ control = ADV_INB(adv, ADV_CHIP_CTRL) & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG | ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET | ADV_CC_BANK_ONE)); if (bank == 1) { control |= ADV_CC_BANK_ONE; } else if (bank == 2) { control |= ADV_CC_DIAG | ADV_CC_BANK_ONE; } ADV_OUTB(adv, ADV_CHIP_CTRL, control);}u_int8_tadv_read_lram_8(struct adv_softc *adv, u_int16_t addr){ u_int8_t byte_data; u_int16_t word_data; /* * LRAM is accessed on 16bit boundaries. */ ADV_OUTW(adv, ADV_LRAM_ADDR, addr & 0xFFFE); word_data = ADV_INW(adv, ADV_LRAM_DATA); if (addr & 1) {#if BYTE_ORDER == BIG_ENDIAN byte_data = (u_int8_t)(word_data & 0xFF);#else byte_data = (u_int8_t)((word_data >> 8) & 0xFF);#endif } else {#if BYTE_ORDER == BIG_ENDIAN byte_data = (u_int8_t)((word_data >> 8) & 0xFF);#else byte_data = (u_int8_t)(word_data & 0xFF);#endif } return (byte_data);}voidadv_write_lram_8(struct adv_softc *adv, u_int16_t addr, u_int8_t value){ u_int16_t word_data; word_data = adv_read_lram_16(adv, addr & 0xFFFE); if (addr & 1) { word_data &= 0x00FF; word_data |= (((u_int8_t)value << 8) & 0xFF00); } else { word_data &= 0xFF00; word_data |= ((u_int8_t)value & 0x00FF); } adv_write_lram_16(adv, addr & 0xFFFE, word_data);}u_int16_tadv_read_lram_16(struct adv_softc *adv, u_int16_t addr){ ADV_OUTW(adv, ADV_LRAM_ADDR, addr); return (ADV_INW(adv, ADV_LRAM_DATA));}voidadv_write_lram_16(struct adv_softc *adv, u_int16_t addr, u_int16_t value){ ADV_OUTW(adv, ADV_LRAM_ADDR, addr); ADV_OUTW(adv, ADV_LRAM_DATA, value);}/* * Determine if there is a board at "iobase" by looking * for the AdvanSys signatures. Return 1 if a board is * found, 0 otherwise. */int adv_find_signature(bus_space_tag_t tag, bus_space_handle_t bsh){ u_int16_t signature; if (bus_space_read_1(tag, bsh, ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) { signature = bus_space_read_2(tag, bsh, ADV_SIGNATURE_WORD); if ((signature == ADV_1000_ID0W) || (signature == ADV_1000_ID0W_FIX)) return (1); } return (0);}voidadv_lib_init(struct adv_softc *adv){ if ((adv->type & ADV_ULTRA) != 0) { adv->sdtr_period_tbl = adv_sdtr_period_tbl_ultra; adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl_ultra); } else { adv->sdtr_period_tbl = adv_sdtr_period_tbl; adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl); }}u_int16_tadv_get_eeprom_config(struct adv_softc *adv, struct adv_eeprom_config *eeprom_config){ u_int16_t sum; u_int16_t *wbuf; u_int8_t cfg_beg; u_int8_t cfg_end; u_int8_t s_addr; wbuf = (u_int16_t *)eeprom_config; sum = 0; for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { *wbuf = adv_read_eeprom_16(adv, s_addr); sum += *wbuf; } if (adv->type & ADV_VL) { cfg_beg = ADV_EEPROM_CFG_BEG_VL; cfg_end = ADV_EEPROM_MAX_ADDR_VL; } else { cfg_beg = ADV_EEPROM_CFG_BEG; cfg_end = ADV_EEPROM_MAX_ADDR; } for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { *wbuf = adv_read_eeprom_16(adv, s_addr); sum += *wbuf;#if ADV_DEBUG_EEPROM
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?