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 + -
显示快捷键?