⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aic79xx_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Core routines and tables shareable across OS platforms. * * Copyright (c) 1994-2002 Justin T. Gibbs. * Copyright (c) 2000-2003 Adaptec Inc. * 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. * 2. Redistributions in binary form must reproduce at minimum a disclaimer *    substantially similar to the "NO WARRANTY" disclaimer below *    ("Disclaimer") and any redistribution must be conditioned upon *    including a substantially similar Disclaimer requirement for further *    binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names *    of any contributors may be used to endorse or promote products derived *    from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. * * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#202 $ * * $FreeBSD$ */#ifdef __linux__#include "aic79xx_osm.h"#include "aic79xx_inline.h"#include "aicasm/aicasm_insformat.h"#else#include <dev/aic7xxx/aic79xx_osm.h>#include <dev/aic7xxx/aic79xx_inline.h>#include <dev/aic7xxx/aicasm/aicasm_insformat.h>#endif/***************************** Lookup Tables **********************************/char *ahd_chip_names[] ={	"NONE",	"aic7901",	"aic7902",	"aic7901A"};static const u_int num_chip_names = NUM_ELEMENTS(ahd_chip_names);/* * Hardware error codes. */struct ahd_hard_error_entry {        uint8_t errno;	char *errmesg;};static struct ahd_hard_error_entry ahd_hard_errors[] = {	{ DSCTMOUT,	"Discard Timer has timed out" },	{ ILLOPCODE,	"Illegal Opcode in sequencer program" },	{ SQPARERR,	"Sequencer Parity Error" },	{ DPARERR,	"Data-path Parity Error" },	{ MPARERR,	"Scratch or SCB Memory Parity Error" },	{ CIOPARERR,	"CIOBUS Parity Error" },};static const u_int num_errors = NUM_ELEMENTS(ahd_hard_errors);static struct ahd_phase_table_entry ahd_phase_table[] ={	{ P_DATAOUT,	MSG_NOOP,		"in Data-out phase"	},	{ P_DATAIN,	MSG_INITIATOR_DET_ERR,	"in Data-in phase"	},	{ P_DATAOUT_DT,	MSG_NOOP,		"in DT Data-out phase"	},	{ P_DATAIN_DT,	MSG_INITIATOR_DET_ERR,	"in DT Data-in phase"	},	{ P_COMMAND,	MSG_NOOP,		"in Command phase"	},	{ P_MESGOUT,	MSG_NOOP,		"in Message-out phase"	},	{ P_STATUS,	MSG_INITIATOR_DET_ERR,	"in Status phase"	},	{ P_MESGIN,	MSG_PARITY_ERROR,	"in Message-in phase"	},	{ P_BUSFREE,	MSG_NOOP,		"while idle"		},	{ 0,		MSG_NOOP,		"in unknown phase"	}};/* * In most cases we only wish to itterate over real phases, so * exclude the last element from the count. */static const u_int num_phases = NUM_ELEMENTS(ahd_phase_table) - 1;/* Our Sequencer Program */#include "aic79xx_seq.h"/**************************** Function Declarations ***************************/static void		ahd_handle_transmission_error(struct ahd_softc *ahd);static void		ahd_handle_lqiphase_error(struct ahd_softc *ahd,						  u_int lqistat1);static int		ahd_handle_pkt_busfree(struct ahd_softc *ahd,					       u_int busfreetime);static int		ahd_handle_nonpkt_busfree(struct ahd_softc *ahd);static void		ahd_handle_proto_violation(struct ahd_softc *ahd);static void		ahd_force_renegotiation(struct ahd_softc *ahd,						struct ahd_devinfo *devinfo);static struct ahd_tmode_tstate*			ahd_alloc_tstate(struct ahd_softc *ahd,					 u_int scsi_id, char channel);#ifdef AHD_TARGET_MODEstatic void		ahd_free_tstate(struct ahd_softc *ahd,					u_int scsi_id, char channel, int force);#endifstatic void		ahd_devlimited_syncrate(struct ahd_softc *ahd,					        struct ahd_initiator_tinfo *,						u_int *period,						u_int *ppr_options,						role_t role);static void		ahd_update_neg_table(struct ahd_softc *ahd,					     struct ahd_devinfo *devinfo,					     struct ahd_transinfo *tinfo);static void		ahd_update_pending_scbs(struct ahd_softc *ahd);static void		ahd_fetch_devinfo(struct ahd_softc *ahd,					  struct ahd_devinfo *devinfo);static void		ahd_scb_devinfo(struct ahd_softc *ahd,					struct ahd_devinfo *devinfo,					struct scb *scb);static void		ahd_setup_initiator_msgout(struct ahd_softc *ahd,						   struct ahd_devinfo *devinfo,						   struct scb *scb);static void		ahd_build_transfer_msg(struct ahd_softc *ahd,					       struct ahd_devinfo *devinfo);static void		ahd_construct_sdtr(struct ahd_softc *ahd,					   struct ahd_devinfo *devinfo,					   u_int period, u_int offset);static void		ahd_construct_wdtr(struct ahd_softc *ahd,					   struct ahd_devinfo *devinfo,					   u_int bus_width);static void		ahd_construct_ppr(struct ahd_softc *ahd,					  struct ahd_devinfo *devinfo,					  u_int period, u_int offset,					  u_int bus_width, u_int ppr_options);static void		ahd_clear_msg_state(struct ahd_softc *ahd);static void		ahd_handle_message_phase(struct ahd_softc *ahd);typedef enum {	AHDMSG_1B,	AHDMSG_2B,	AHDMSG_EXT} ahd_msgtype;static int		ahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type,				     u_int msgval, int full);static int		ahd_parse_msg(struct ahd_softc *ahd,				      struct ahd_devinfo *devinfo);static int		ahd_handle_msg_reject(struct ahd_softc *ahd,					      struct ahd_devinfo *devinfo);static void		ahd_handle_ign_wide_residue(struct ahd_softc *ahd,						struct ahd_devinfo *devinfo);static void		ahd_reinitialize_dataptrs(struct ahd_softc *ahd);static void		ahd_handle_devreset(struct ahd_softc *ahd,					    struct ahd_devinfo *devinfo,					    u_int lun, cam_status status,					    char *message, int verbose_level);#ifdef AHD_TARGET_MODEstatic void		ahd_setup_target_msgin(struct ahd_softc *ahd,					       struct ahd_devinfo *devinfo,					       struct scb *scb);#endifstatic u_int		ahd_sglist_size(struct ahd_softc *ahd);static u_int		ahd_sglist_allocsize(struct ahd_softc *ahd);static bus_dmamap_callback_t			ahd_dmamap_cb; static void		ahd_initialize_hscbs(struct ahd_softc *ahd);static int		ahd_init_scbdata(struct ahd_softc *ahd);static void		ahd_fini_scbdata(struct ahd_softc *ahd);static void		ahd_setup_iocell_workaround(struct ahd_softc *ahd);static void		ahd_iocell_first_selection(struct ahd_softc *ahd);static void		ahd_add_col_list(struct ahd_softc *ahd,					 struct scb *scb, u_int col_idx);static void		ahd_rem_col_list(struct ahd_softc *ahd,					 struct scb *scb);static void		ahd_chip_init(struct ahd_softc *ahd);static void		ahd_qinfifo_requeue(struct ahd_softc *ahd,					    struct scb *prev_scb,					    struct scb *scb);static int		ahd_qinfifo_count(struct ahd_softc *ahd);static int		ahd_search_scb_list(struct ahd_softc *ahd, int target,					    char channel, int lun, u_int tag,					    role_t role, uint32_t status,					    ahd_search_action action,					    u_int *list_head, u_int tid);static void		ahd_stitch_tid_list(struct ahd_softc *ahd,					    u_int tid_prev, u_int tid_cur,					    u_int tid_next);static void		ahd_add_scb_to_free_list(struct ahd_softc *ahd,						 u_int scbid);static u_int		ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid,				     u_int prev, u_int next, u_int tid);static void		ahd_reset_current_bus(struct ahd_softc *ahd);static ahd_callback_t	ahd_reset_poll;static ahd_callback_t	ahd_stat_timer;#ifdef AHD_DUMP_SEQstatic void		ahd_dumpseq(struct ahd_softc *ahd);#endifstatic void		ahd_loadseq(struct ahd_softc *ahd);static int		ahd_check_patch(struct ahd_softc *ahd,					struct patch **start_patch,					u_int start_instr, u_int *skip_addr);static u_int		ahd_resolve_seqaddr(struct ahd_softc *ahd,					    u_int address);static void		ahd_download_instr(struct ahd_softc *ahd,					   u_int instrptr, uint8_t *dconsts);static int		ahd_probe_stack_size(struct ahd_softc *ahd);static int		ahd_scb_active_in_fifo(struct ahd_softc *ahd,					       struct scb *scb);static void		ahd_run_data_fifo(struct ahd_softc *ahd,					  struct scb *scb);#ifdef AHD_TARGET_MODEstatic void		ahd_queue_lstate_event(struct ahd_softc *ahd,					       struct ahd_tmode_lstate *lstate,					       u_int initiator_id,					       u_int event_type,					       u_int event_arg);static void		ahd_update_scsiid(struct ahd_softc *ahd,					  u_int targid_mask);static int		ahd_handle_target_cmd(struct ahd_softc *ahd,					      struct target_cmd *cmd);#endif/******************************** Private Inlines *****************************/static __inline void	ahd_assert_atn(struct ahd_softc *ahd);static __inline int	ahd_currently_packetized(struct ahd_softc *ahd);static __inline int	ahd_set_active_fifo(struct ahd_softc *ahd);static __inline voidahd_assert_atn(struct ahd_softc *ahd){	ahd_outb(ahd, SCSISIGO, ATNO);}/* * Determine if the current connection has a packetized * agreement.  This does not necessarily mean that we * are currently in a packetized transfer.  We could * just as easily be sending or receiving a message. */static __inline intahd_currently_packetized(struct ahd_softc *ahd){	ahd_mode_state	 saved_modes;	int		 packetized;	saved_modes = ahd_save_modes(ahd);	if ((ahd->bugs & AHD_PKTIZED_STATUS_BUG) != 0) {		/*		 * The packetized bit refers to the last		 * connection, not the current one.  Check		 * for non-zero LQISTATE instead.		 */		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);		packetized = ahd_inb(ahd, LQISTATE) != 0;	} else {		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);		packetized = ahd_inb(ahd, LQISTAT2) & PACKETIZED;	}	ahd_restore_modes(ahd, saved_modes);	return (packetized);}static __inline intahd_set_active_fifo(struct ahd_softc *ahd){	u_int active_fifo;	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);	active_fifo = ahd_inb(ahd, DFFSTAT) & CURRFIFO;	switch (active_fifo) {	case 0:	case 1:		ahd_set_modes(ahd, active_fifo, active_fifo);		return (1);	default:		return (0);	}}/************************* Sequencer Execution Control ************************//* * Restart the sequencer program from address zero */voidahd_restart(struct ahd_softc *ahd){	ahd_pause(ahd);	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);	/* No more pending messages */	ahd_clear_msg_state(ahd);	ahd_outb(ahd, SCSISIGO, 0);		/* De-assert BSY */	ahd_outb(ahd, MSG_OUT, MSG_NOOP);	/* No message to send */	ahd_outb(ahd, SXFRCTL1, ahd_inb(ahd, SXFRCTL1) & ~BITBUCKET);	ahd_outb(ahd, SEQINTCTL, 0);	ahd_outb(ahd, LASTPHASE, P_BUSFREE);	ahd_outb(ahd, SEQ_FLAGS, 0);	ahd_outb(ahd, SAVED_SCSIID, 0xFF);	ahd_outb(ahd, SAVED_LUN, 0xFF);	/*	 * Ensure that the sequencer's idea of TQINPOS	 * matches our own.  The sequencer increments TQINPOS	 * only after it sees a DMA complete and a reset could	 * occur before the increment leaving the kernel to believe	 * the command arrived but the sequencer to not.	 */	ahd_outb(ahd, TQINPOS, ahd->tqinfifonext);	/* Always allow reselection */	ahd_outb(ahd, SCSISEQ1,		 ahd_inb(ahd, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP));	ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);	ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET);	ahd_unpause(ahd);}voidahd_clear_fifo(struct ahd_softc *ahd, u_int fifo){	ahd_mode_state	 saved_modes;#ifdef AHD_DEBUG	if ((ahd_debug & AHD_SHOW_FIFOS) != 0)		printf("%s: Clearing FIFO %d\n", ahd_name(ahd), fifo);#endif	saved_modes = ahd_save_modes(ahd);	ahd_set_modes(ahd, fifo, fifo);	ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT);	if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0)		ahd_outb(ahd, CCSGCTL, CCSGRESET);	ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR);	ahd_outb(ahd, SG_STATE, 0);	ahd_restore_modes(ahd, saved_modes);}/************************* Input/Output Queues ********************************//* * Flush and completed commands that are sitting in the command * complete queues down on the chip but have yet to be dma'ed back up. */voidahd_flush_qoutfifo(struct ahd_softc *ahd){	struct		scb *scb;	ahd_mode_state	saved_modes;	u_int		saved_scbptr;	u_int		ccscbctl;	u_int		scbid;	u_int		next_scbid;	saved_modes = ahd_save_modes(ahd);	/*	 * Complete any SCBs that just finished being	 * DMA'ed into the qoutfifo.	 */	ahd_run_qoutfifo(ahd);	/*	 * Flush the good status FIFO for compelted packetized commands.	 */	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);	saved_scbptr = ahd_get_scbptr(ahd);	while ((ahd_inb(ahd, LQISTAT2) & LQIGSAVAIL) != 0) {		u_int fifo_mode;		u_int i;				scbid = (ahd_inb(ahd, GSFIFO+1) << 8)		      | ahd_inb(ahd, GSFIFO);		scb = ahd_lookup_scb(ahd, scbid);		if (scb == NULL) {			printf("%s: Warning - GSFIFO SCB %d invalid\n",			       ahd_name(ahd), scbid);			continue;		}		/*		 * Determine if this transaction is still active in		 * any FIFO.  If it is, we must flush that FIFO to		 * the host before completing the  command.		 */		fifo_mode = 0;		for (i = 0; i < 2; i++) {			/* Toggle to the other mode. */			fifo_mode ^= 1;			ahd_set_modes(ahd, fifo_mode, fifo_mode);			if (ahd_scb_active_in_fifo(ahd, scb) == 0)				continue;			ahd_run_data_fifo(ahd, scb);			/*			 * Clearing this transaction in this FIFO may			 * cause a CFG4DATA for this same transaction			 * to assert in the other FIFO.  Make sure we			 * loop one more time and check the other FIFO.			 */			i = 0;		}		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);		ahd_set_scbptr(ahd, scbid);		if ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_LIST_NULL) == 0		 && ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_FULL_RESID) != 0		  || (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR)		      & SG_LIST_NULL) != 0)) {			u_int comp_head;			/*			 * The transfer completed with a residual.			 * Place this SCB on the complete DMA list			 * so that we Update our in-core copy of the			 * SCB before completing the command.			 */			ahd_outb(ahd, SCB_SCSI_STATUS, 0);			ahd_outb(ahd, SCB_SGPTR,				 ahd_inb_scbram(ahd, SCB_SGPTR)				 | SG_STATUS_VALID);			ahd_outw(ahd, SCB_TAG, SCB_GET_TAG(scb));			comp_head = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -