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

📄 aic7xxx_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-2002 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/aic7xxx.c#155 $ */#ifdef __linux__#include "aic7xxx_osm.h"#include "aic7xxx_inline.h"#include "aicasm/aicasm_insformat.h"#else#include <dev/aic7xxx/aic7xxx_osm.h>#include <dev/aic7xxx/aic7xxx_inline.h>#include <dev/aic7xxx/aicasm/aicasm_insformat.h>#endif/***************************** Lookup Tables **********************************/char *ahc_chip_names[] ={	"NONE",	"aic7770",	"aic7850",	"aic7855",	"aic7859",	"aic7860",	"aic7870",	"aic7880",	"aic7895",	"aic7895C",	"aic7890/91",	"aic7896/97",	"aic7892",	"aic7899"};static const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names);/* * Hardware error codes. */struct ahc_hard_error_entry {        uint8_t errno;	char *errmesg;};static struct ahc_hard_error_entry ahc_hard_errors[] = {	{ ILLHADDR,	"Illegal Host Access" },	{ ILLSADDR,	"Illegal Sequencer Address referrenced" },	{ ILLOPCODE,	"Illegal Opcode in sequencer program" },	{ SQPARERR,	"Sequencer Parity Error" },	{ DPARERR,	"Data-path Parity Error" },	{ MPARERR,	"Scratch or SCB Memory Parity Error" },	{ PCIERRSTAT,	"PCI Error detected" },	{ CIOPARERR,	"CIOBUS Parity Error" },};static const u_int num_errors = NUM_ELEMENTS(ahc_hard_errors);static struct ahc_phase_table_entry ahc_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(ahc_phase_table) - 1;/* * Valid SCSIRATE values.  (p. 3-17) * Provides a mapping of tranfer periods in ns to the proper value to * stick in the scsixfer reg. */static struct ahc_syncrate ahc_syncrates[] ={      /* ultra2    fast/ultra  period     rate */	{ 0x42,      0x000,      9,      "80.0" },	{ 0x03,      0x000,     10,      "40.0" },	{ 0x04,      0x000,     11,      "33.0" },	{ 0x05,      0x100,     12,      "20.0" },	{ 0x06,      0x110,     15,      "16.0" },	{ 0x07,      0x120,     18,      "13.4" },	{ 0x08,      0x000,     25,      "10.0" },	{ 0x19,      0x010,     31,      "8.0"  },	{ 0x1a,      0x020,     37,      "6.67" },	{ 0x1b,      0x030,     43,      "5.7"  },	{ 0x1c,      0x040,     50,      "5.0"  },	{ 0x00,      0x050,     56,      "4.4"  },	{ 0x00,      0x060,     62,      "4.0"  },	{ 0x00,      0x070,     68,      "3.6"  },	{ 0x00,      0x000,      0,      NULL   }};/* Our Sequencer Program */#include "aic7xxx_seq.h"/**************************** Function Declarations ***************************/static void		ahc_force_renegotiation(struct ahc_softc *ahc,						struct ahc_devinfo *devinfo);static struct ahc_tmode_tstate*			ahc_alloc_tstate(struct ahc_softc *ahc,					 u_int scsi_id, char channel);#ifdef AHC_TARGET_MODEstatic void		ahc_free_tstate(struct ahc_softc *ahc,					u_int scsi_id, char channel, int force);#endifstatic struct ahc_syncrate*			ahc_devlimited_syncrate(struct ahc_softc *ahc,					        struct ahc_initiator_tinfo *,						u_int *period,						u_int *ppr_options,						role_t role);static void		ahc_update_pending_scbs(struct ahc_softc *ahc);static void		ahc_fetch_devinfo(struct ahc_softc *ahc,					  struct ahc_devinfo *devinfo);static void		ahc_scb_devinfo(struct ahc_softc *ahc,					struct ahc_devinfo *devinfo,					struct scb *scb);static void		ahc_assert_atn(struct ahc_softc *ahc);static void		ahc_setup_initiator_msgout(struct ahc_softc *ahc,						   struct ahc_devinfo *devinfo,						   struct scb *scb);static void		ahc_build_transfer_msg(struct ahc_softc *ahc,					       struct ahc_devinfo *devinfo);static void		ahc_construct_sdtr(struct ahc_softc *ahc,					   struct ahc_devinfo *devinfo,					   u_int period, u_int offset);static void		ahc_construct_wdtr(struct ahc_softc *ahc,					   struct ahc_devinfo *devinfo,					   u_int bus_width);static void		ahc_construct_ppr(struct ahc_softc *ahc,					  struct ahc_devinfo *devinfo,					  u_int period, u_int offset,					  u_int bus_width, u_int ppr_options);static void		ahc_clear_msg_state(struct ahc_softc *ahc);static void		ahc_handle_proto_violation(struct ahc_softc *ahc);static void		ahc_handle_message_phase(struct ahc_softc *ahc);typedef enum {	AHCMSG_1B,	AHCMSG_2B,	AHCMSG_EXT} ahc_msgtype;static int		ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type,				     u_int msgval, int full);static int		ahc_parse_msg(struct ahc_softc *ahc,				      struct ahc_devinfo *devinfo);static int		ahc_handle_msg_reject(struct ahc_softc *ahc,					      struct ahc_devinfo *devinfo);static void		ahc_handle_ign_wide_residue(struct ahc_softc *ahc,						struct ahc_devinfo *devinfo);static void		ahc_reinitialize_dataptrs(struct ahc_softc *ahc);static void		ahc_handle_devreset(struct ahc_softc *ahc,					    struct ahc_devinfo *devinfo,					    cam_status status, char *message,					    int verbose_level);#ifdef AHC_TARGET_MODEstatic void		ahc_setup_target_msgin(struct ahc_softc *ahc,					       struct ahc_devinfo *devinfo,					       struct scb *scb);#endifstatic bus_dmamap_callback_t	ahc_dmamap_cb; static void			ahc_build_free_scb_list(struct ahc_softc *ahc);static int			ahc_init_scbdata(struct ahc_softc *ahc);static void			ahc_fini_scbdata(struct ahc_softc *ahc);static void		ahc_qinfifo_requeue(struct ahc_softc *ahc,					    struct scb *prev_scb,					    struct scb *scb);static int		ahc_qinfifo_count(struct ahc_softc *ahc);static u_int		ahc_rem_scb_from_disc_list(struct ahc_softc *ahc,						   u_int prev, u_int scbptr);static void		ahc_add_curscb_to_free_list(struct ahc_softc *ahc);static u_int		ahc_rem_wscb(struct ahc_softc *ahc,				     u_int scbpos, u_int prev);static void		ahc_reset_current_bus(struct ahc_softc *ahc);#ifdef AHC_DUMP_SEQstatic void		ahc_dumpseq(struct ahc_softc *ahc);#endifstatic int		ahc_loadseq(struct ahc_softc *ahc);static int		ahc_check_patch(struct ahc_softc *ahc,					struct patch **start_patch,					u_int start_instr, u_int *skip_addr);static void		ahc_download_instr(struct ahc_softc *ahc,					   u_int instrptr, uint8_t *dconsts);#ifdef AHC_TARGET_MODEstatic void		ahc_queue_lstate_event(struct ahc_softc *ahc,					       struct ahc_tmode_lstate *lstate,					       u_int initiator_id,					       u_int event_type,					       u_int event_arg);static void		ahc_update_scsiid(struct ahc_softc *ahc,					  u_int targid_mask);static int		ahc_handle_target_cmd(struct ahc_softc *ahc,					      struct target_cmd *cmd);#endif/************************* Sequencer Execution Control ************************//* * Restart the sequencer program from address zero */voidahc_restart(struct ahc_softc *ahc){	ahc_pause(ahc);	/* No more pending messages. */	ahc_clear_msg_state(ahc);	ahc_outb(ahc, SCSISIGO, 0);		/* De-assert BSY */	ahc_outb(ahc, MSG_OUT, MSG_NOOP);	/* No message to send */	ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET);	ahc_outb(ahc, LASTPHASE, P_BUSFREE);	ahc_outb(ahc, SAVED_SCSIID, 0xFF);	ahc_outb(ahc, 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.	 */	ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);	/* Always allow reselection */	ahc_outb(ahc, SCSISEQ,		 ahc_inb(ahc, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP));	if ((ahc->features & AHC_CMD_CHAN) != 0) {		/* Ensure that no DMA operations are in progress */		ahc_outb(ahc, CCSCBCNT, 0);		ahc_outb(ahc, CCSGCTL, 0);		ahc_outb(ahc, CCSCBCTL, 0);	}	/*	 * If we were in the process of DMA'ing SCB data into	 * an SCB, replace that SCB on the free list.  This prevents	 * an SCB leak.	 */	if ((ahc_inb(ahc, SEQ_FLAGS2) & SCB_DMA) != 0) {		ahc_add_curscb_to_free_list(ahc);		ahc_outb(ahc, SEQ_FLAGS2,			 ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA);	}	/*	 * Clear any pending sequencer interrupt.  It is no	 * longer relevant since we're resetting the Program	 * Counter.	 */	ahc_outb(ahc, CLRINT, CLRSEQINT);	ahc_outb(ahc, MWI_RESIDUAL, 0);	ahc_outb(ahc, SEQCTL, ahc->seqctl);	ahc_outb(ahc, SEQADDR0, 0);	ahc_outb(ahc, SEQADDR1, 0);	ahc_unpause(ahc);}/************************* Input/Output Queues ********************************/voidahc_run_qoutfifo(struct ahc_softc *ahc){	struct scb *scb;	u_int  scb_index;	ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD);	while (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) {		scb_index = ahc->qoutfifo[ahc->qoutfifonext];		if ((ahc->qoutfifonext & 0x03) == 0x03) {			u_int modnext;			/*			 * Clear 32bits of QOUTFIFO at a time			 * so that we don't clobber an incoming			 * byte DMA to the array on architectures			 * that only support 32bit load and store			 * operations.			 */			modnext = ahc->qoutfifonext & ~0x3;			*((uint32_t *)(&ahc->qoutfifo[modnext])) = 0xFFFFFFFFUL;			ahc_dmamap_sync(ahc, ahc->shared_data_dmat,					ahc->shared_data_dmamap,					/*offset*/modnext, /*len*/4,					BUS_DMASYNC_PREREAD);		}		ahc->qoutfifonext++;		scb = ahc_lookup_scb(ahc, scb_index);		if (scb == NULL) {			printf("%s: WARNING no command for scb %d "			       "(cmdcmplt)\nQOUTPOS = %d\n",			       ahc_name(ahc), scb_index,			       (ahc->qoutfifonext - 1) & 0xFF);			continue;		}		/*		 * Save off the residual		 * if there is one.		 */		ahc_update_residual(ahc, scb);		ahc_done(ahc, scb);	}}voidahc_run_untagged_queues(struct ahc_softc *ahc){	int i;	for (i = 0; i < 16; i++)		ahc_run_untagged_queue(ahc, &ahc->untagged_queues[i]);}voidahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue){	struct scb *scb;	if (ahc->untagged_queue_lock != 0)		return;	if ((scb = TAILQ_FIRST(queue)) != NULL	 && (scb->flags & SCB_ACTIVE) == 0) {		scb->flags |= SCB_ACTIVE;		ahc_queue_scb(ahc, scb);	}}/************************* Interrupt Handling *********************************/voidahc_handle_brkadrint(struct ahc_softc *ahc){	/*	 * We upset the sequencer :-(	 * Lookup the error message	 */	int i;	int error;	error = ahc_inb(ahc, ERROR);	for (i = 0; error != 1 && i < num_errors; i++)		error >>= 1;	printf("%s: brkadrint, %s at seqaddr = 0x%x\n",	       ahc_name(ahc), ahc_hard_errors[i].errmesg,	       ahc_inb(ahc, SEQADDR0) |	       (ahc_inb(ahc, SEQADDR1) << 8));	ahc_dump_card_state(ahc);	/* Tell everyone that this HBA is no longer available */	ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS,		       CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN,		       CAM_NO_HBA);	/* Disable all interrupt sources by resetting the controller */	ahc_shutdown(ahc);}voidahc_handle_seqint(struct ahc_softc *ahc, u_int intstat){	struct scb *scb;	struct ahc_devinfo devinfo;		ahc_fetch_devinfo(ahc, &devinfo);	/*	 * Clear the upper byte that holds SEQINT status	 * codes and clear the SEQINT bit. We will unpause	 * the sequencer, if appropriate, after servicing	 * the request.	 */	ahc_outb(ahc, CLRINT, CLRSEQINT);	switch (intstat & SEQINT_MASK) {	case BAD_STATUS:	{		u_int  scb_index;		struct hardware_scb *hscb;		/*		 * Set the default return value to 0 (don't		 * send sense).  The sense code will change		 * this if needed.		 */		ahc_outb(ahc, RETURN_1, 0);		/*		 * The sequencer will notify us when a command		 * has an error that would be of interest to		 * the kernel.  This allows us to leave the sequencer		 * running in the common case of command completes		 * without error.  The sequencer will already have		 * dma'd the SCB back up to us, so we can reference		 * the in kernel copy directly.		 */		scb_index = ahc_inb(ahc, SCB_TAG);		scb = ahc_lookup_scb(ahc, scb_index);		if (scb == NULL) {			ahc_print_devinfo(ahc, &devinfo);			printf("ahc_intr - referenced scb "			       "not valid during seqint 0x%x scb(%d)\n",			       intstat, scb_index);			ahc_dump_card_state(ahc);			panic("for safety");			goto unpause;		}		hscb = scb->hscb; 

⌨️ 快捷键说明

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