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

📄 aic7xxx_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo,		   u_int *bus_width, role_t role){	switch (*bus_width) {	default:		if (ahc->features & AHC_WIDE) {			/* Respond Wide */			*bus_width = MSG_EXT_WDTR_BUS_16_BIT;			break;		}		/* FALLTHROUGH */	case MSG_EXT_WDTR_BUS_8_BIT:		*bus_width = MSG_EXT_WDTR_BUS_8_BIT;		break;	}	if (tinfo != NULL) {		if (role == ROLE_TARGET)			*bus_width = MIN(tinfo->user.width, *bus_width);		else			*bus_width = MIN(tinfo->goal.width, *bus_width);	}}/* * Update the bitmask of targets for which the controller should * negotiate with at the next convenient oportunity.  This currently * means the next time we send the initial identify messages for * a new transaction. */intahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,		       struct ahc_tmode_tstate *tstate,		       struct ahc_initiator_tinfo *tinfo, ahc_neg_type neg_type){	u_int auto_negotiate_orig;	auto_negotiate_orig = tstate->auto_negotiate;	if (neg_type == AHC_NEG_ALWAYS) {		/*		 * Force our "current" settings to be		 * unknown so that unless a bus reset		 * occurs the need to renegotiate is		 * recorded persistently.		 */		if ((ahc->features & AHC_WIDE) != 0)			tinfo->curr.width = AHC_WIDTH_UNKNOWN;		tinfo->curr.period = AHC_PERIOD_UNKNOWN;		tinfo->curr.offset = AHC_OFFSET_UNKNOWN;	}	if (tinfo->curr.period != tinfo->goal.period	 || tinfo->curr.width != tinfo->goal.width	 || tinfo->curr.offset != tinfo->goal.offset	 || tinfo->curr.ppr_options != tinfo->goal.ppr_options	 || (neg_type == AHC_NEG_IF_NON_ASYNC	  && (tinfo->goal.offset != 0	   || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT	   || tinfo->goal.ppr_options != 0)))		tstate->auto_negotiate |= devinfo->target_mask;	else		tstate->auto_negotiate &= ~devinfo->target_mask;	return (auto_negotiate_orig != tstate->auto_negotiate);}/* * Update the user/goal/curr tables of synchronous negotiation * parameters as well as, in the case of a current or active update, * any data structures on the host controller.  In the case of an * active update, the specified target is currently talking to us on * the bus, so the transfer parameter update must take effect * immediately. */voidahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,		 struct ahc_syncrate *syncrate, u_int period,		 u_int offset, u_int ppr_options, u_int type, int paused){	struct	ahc_initiator_tinfo *tinfo;	struct	ahc_tmode_tstate *tstate;	u_int	old_period;	u_int	old_offset;	u_int	old_ppr;	int	active;	int	update_needed;	active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;	update_needed = 0;	if (syncrate == NULL) {		period = 0;		offset = 0;	}	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,				    devinfo->target, &tstate);	if ((type & AHC_TRANS_USER) != 0) {		tinfo->user.period = period;		tinfo->user.offset = offset;		tinfo->user.ppr_options = ppr_options;	}	if ((type & AHC_TRANS_GOAL) != 0) {		tinfo->goal.period = period;		tinfo->goal.offset = offset;		tinfo->goal.ppr_options = ppr_options;	}	old_period = tinfo->curr.period;	old_offset = tinfo->curr.offset;	old_ppr	   = tinfo->curr.ppr_options;	if ((type & AHC_TRANS_CUR) != 0	 && (old_period != period	  || old_offset != offset	  || old_ppr != ppr_options)) {		u_int	scsirate;		update_needed++;		scsirate = tinfo->scsirate;		if ((ahc->features & AHC_ULTRA2) != 0) {			scsirate &= ~(SXFR_ULTRA2|SINGLE_EDGE|ENABLE_CRC);			if (syncrate != NULL) {				scsirate |= syncrate->sxfr_u2;				if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0)					scsirate |= ENABLE_CRC;				else					scsirate |= SINGLE_EDGE;			}		} else {			scsirate &= ~(SXFR|SOFS);			/*			 * Ensure Ultra mode is set properly for			 * this target.			 */			tstate->ultraenb &= ~devinfo->target_mask;			if (syncrate != NULL) {				if (syncrate->sxfr & ULTRA_SXFR) {					tstate->ultraenb |=						devinfo->target_mask;				}				scsirate |= syncrate->sxfr & SXFR;				scsirate |= offset & SOFS;			}			if (active) {				u_int sxfrctl0;				sxfrctl0 = ahc_inb(ahc, SXFRCTL0);				sxfrctl0 &= ~FAST20;				if (tstate->ultraenb & devinfo->target_mask)					sxfrctl0 |= FAST20;				ahc_outb(ahc, SXFRCTL0, sxfrctl0);			}		}		if (active) {			ahc_outb(ahc, SCSIRATE, scsirate);			if ((ahc->features & AHC_ULTRA2) != 0)				ahc_outb(ahc, SCSIOFFSET, offset);		}		tinfo->scsirate = scsirate;		tinfo->curr.period = period;		tinfo->curr.offset = offset;		tinfo->curr.ppr_options = ppr_options;		ahc_send_async(ahc, devinfo->channel, devinfo->target,			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);		if (bootverbose) {			if (offset != 0) {				printf("%s: target %d synchronous at %sMHz%s, "				       "offset = 0x%x\n", ahc_name(ahc),				       devinfo->target, syncrate->rate,				       (ppr_options & MSG_EXT_PPR_DT_REQ)				       ? " DT" : "", offset);			} else {				printf("%s: target %d using "				       "asynchronous transfers\n",				       ahc_name(ahc), devinfo->target);			}		}	}	update_needed += ahc_update_neg_request(ahc, devinfo, tstate,						tinfo, AHC_NEG_TO_GOAL);	if (update_needed)		ahc_update_pending_scbs(ahc);}/* * Update the user/goal/curr tables of wide negotiation * parameters as well as, in the case of a current or active update, * any data structures on the host controller.  In the case of an * active update, the specified target is currently talking to us on * the bus, so the transfer parameter update must take effect * immediately. */voidahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,	      u_int width, u_int type, int paused){	struct	ahc_initiator_tinfo *tinfo;	struct	ahc_tmode_tstate *tstate;	u_int	oldwidth;	int	active;	int	update_needed;	active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;	update_needed = 0;	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,				    devinfo->target, &tstate);	if ((type & AHC_TRANS_USER) != 0)		tinfo->user.width = width;	if ((type & AHC_TRANS_GOAL) != 0)		tinfo->goal.width = width;	oldwidth = tinfo->curr.width;	if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) {		u_int	scsirate;		update_needed++;		scsirate =  tinfo->scsirate;		scsirate &= ~WIDEXFER;		if (width == MSG_EXT_WDTR_BUS_16_BIT)			scsirate |= WIDEXFER;		tinfo->scsirate = scsirate;		if (active)			ahc_outb(ahc, SCSIRATE, scsirate);		tinfo->curr.width = width;		ahc_send_async(ahc, devinfo->channel, devinfo->target,			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);		if (bootverbose) {			printf("%s: target %d using %dbit transfers\n",			       ahc_name(ahc), devinfo->target,			       8 * (0x01 << width));		}	}	update_needed += ahc_update_neg_request(ahc, devinfo, tstate,						tinfo, AHC_NEG_TO_GOAL);	if (update_needed)		ahc_update_pending_scbs(ahc);}/* * Update the current state of tagged queuing for a given target. */voidahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,	     ahc_queue_alg alg){ 	ahc_platform_set_tags(ahc, devinfo, alg); 	ahc_send_async(ahc, devinfo->channel, devinfo->target, 		       devinfo->lun, AC_TRANSFER_NEG, &alg);}/* * When the transfer settings for a connection change, update any * in-transit SCBs to contain the new data so the hardware will * be set correctly during future (re)selections. */static voidahc_update_pending_scbs(struct ahc_softc *ahc){	struct	scb *pending_scb;	int	pending_scb_count;	int	i;	int	paused;	u_int	saved_scbptr;	/*	 * Traverse the pending SCB list and ensure that all of the	 * SCBs there have the proper settings.	 */	pending_scb_count = 0;	LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) {		struct ahc_devinfo devinfo;		struct hardware_scb *pending_hscb;		struct ahc_initiator_tinfo *tinfo;		struct ahc_tmode_tstate *tstate;		ahc_scb_devinfo(ahc, &devinfo, pending_scb);		tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,					    devinfo.our_scsiid,					    devinfo.target, &tstate);		pending_hscb = pending_scb->hscb;		pending_hscb->control &= ~ULTRAENB;		if ((tstate->ultraenb & devinfo.target_mask) != 0)			pending_hscb->control |= ULTRAENB;		pending_hscb->scsirate = tinfo->scsirate;		pending_hscb->scsioffset = tinfo->curr.offset;		if ((tstate->auto_negotiate & devinfo.target_mask) == 0		 && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) {			pending_scb->flags &= ~SCB_AUTO_NEGOTIATE;			pending_hscb->control &= ~MK_MESSAGE;		}		ahc_sync_scb(ahc, pending_scb,			     BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);		pending_scb_count++;	}	if (pending_scb_count == 0)		return;	if (ahc_is_paused(ahc)) {		paused = 1;	} else {		paused = 0;		ahc_pause(ahc);	}	saved_scbptr = ahc_inb(ahc, SCBPTR);	/* Ensure that the hscbs down on the card match the new information */	for (i = 0; i < ahc->scb_data->maxhscbs; i++) {		struct	hardware_scb *pending_hscb;		u_int	control;		u_int	scb_tag;		ahc_outb(ahc, SCBPTR, i);		scb_tag = ahc_inb(ahc, SCB_TAG);		pending_scb = ahc_lookup_scb(ahc, scb_tag);		if (pending_scb == NULL)			continue;		pending_hscb = pending_scb->hscb;		control = ahc_inb(ahc, SCB_CONTROL);		control &= ~(ULTRAENB|MK_MESSAGE);		control |= pending_hscb->control & (ULTRAENB|MK_MESSAGE);		ahc_outb(ahc, SCB_CONTROL, control);		ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate);		ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset);	}	ahc_outb(ahc, SCBPTR, saved_scbptr);	if (paused == 0)		ahc_unpause(ahc);}/**************************** Pathing Information *****************************/static voidahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo){	u_int	saved_scsiid;	role_t	role;	int	our_id;	if (ahc_inb(ahc, SSTAT0) & TARGET)		role = ROLE_TARGET;	else		role = ROLE_INITIATOR;	if (role == ROLE_TARGET	 && (ahc->features & AHC_MULTI_TID) != 0	 && (ahc_inb(ahc, SEQ_FLAGS) 	   & (CMDPHASE_PENDING|TARG_CMD_PENDING|NO_DISCONNECT)) != 0) {		/* We were selected, so pull our id from TARGIDIN */		our_id = ahc_inb(ahc, TARGIDIN) & OID;	} else if ((ahc->features & AHC_ULTRA2) != 0)		our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;	else		our_id = ahc_inb(ahc, SCSIID) & OID;	saved_scsiid = ahc_inb(ahc, SAVED_SCSIID);	ahc_compile_devinfo(devinfo,			    our_id,			    SCSIID_TARGET(ahc, saved_scsiid),			    ahc_inb(ahc, SAVED_LUN),			    SCSIID_CHANNEL(ahc, saved_scsiid),			    role);}struct ahc_phase_table_entry*ahc_lookup_phase_entry(int phase){	struct ahc_phase_table_entry *entry;	struct ahc_phase_table_entry *last_entry;	/*	 * num_phases doesn't include the default entry which	 * will be returned if the phase doesn't match.	 */	last_entry = &ahc_phase_table[num_phases];	for (entry = ahc_phase_table; entry < last_entry; entry++) {		if (phase == entry->phase)			break;	}	return (entry);}voidahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target,		    u_int lun, char channel, role_t role){	devinfo->our_scsiid = our_id;	devinfo->target = target;	devinfo->lun = lun;	devinfo->target_offset = target;	devinfo->channel = channel;	devinfo->role = role;	if (channel == 'B')		devinfo->target_offset += 8;	devinfo->target_mask = (0x01 << devinfo->target_offset);}voidahc_print_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo){	printf("%s:%c:%d:%d: ", ahc_name(ahc), devinfo->channel,	       devinfo->target, devinfo->lun);}static voidahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,		struct scb *scb){	role_t	role;	int	our_id;	our_id = SCSIID_OUR_ID(scb->hscb->scsiid);	role = ROLE_INITIATOR;	if ((scb->flags & SCB_TARGET_SCB) != 0)		role = ROLE_TARGET;	ahc_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahc, scb),			    SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahc, scb), role);}/************************ Message Phase Processing ****************************/static voidahc_assert_atn(struct ahc_softc *ahc){	u_int scsisigo;	scsisigo = ATNO;	if ((ahc->features & AHC_DT) == 0)		scsisigo |= ahc_inb(ahc, SCSISIGI);	ahc_outb(ahc, SCSISIGO, scsisigo);}/* * When an initiator transaction with the MK_MESSAGE flag either reconnects * or enters the initial message out phase, we are interrupted.  Fill our * outgoing message buffer with the appr

⌨️ 快捷键说明

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