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

📄 ahb.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
ahbreset(struct ahb_softc *ahb){	int	wait = 1000;	/* 1 sec enough? */	int	test;	if ((ahb_inb(ahb, PORTADDR) & PORTADDR_ENHANCED) == 0) {		printf("ahb_reset: Controller not in enhanced mode\n");		return (-1);	}	ahb_outb(ahb, CONTROL, CNTRL_HARD_RST);	DELAY(1000);	ahb_outb(ahb, CONTROL, 0);	while (--wait) {		DELAY(1000);		if ((ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_BUSY) == 0)			break;	}	if (wait == 0) {		printf("ahbreset: No answer from aha1742 board\n");		return (-1);	}	if ((test = ahb_inb(ahb, MBOXIN0)) != 0) {		printf("ahb_reset: self test failed, val = 0x%x\n", test);		return (-1);	}	while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {		ahb_outb(ahb, CONTROL, CNTRL_CLRINT);		DELAY(10000);	}	return (0);}static voidahbmapecbs(void *arg, bus_dma_segment_t *segs, int nseg, int error){	struct ahb_softc* ahb;	ahb = (struct ahb_softc*)arg;	ahb->ecb_physbase = segs->ds_addr;	/*	 * Space for adapter inquiry information is on the	 * tail of the ecb array.	 */	ahb->ha_inq_physbase = ahbecbvtop(ahb, &ahb->ecb_array[AHB_NECB]);}static intahbxptattach(struct ahb_softc *ahb){	struct cam_devq *devq;	struct ecb *ecb;	u_int  i;	/* Remeber who are we on the scsi bus */	ahb->scsi_id = ahb_inb(ahb, SCSIDEF) & HSCSIID;	/* Use extended translation?? */    	ahb->extended_trans = ahb_inb(ahb, RESV1) & EXTENDED_TRANS;	/* Fetch adapter inquiry data */	ecb = ahbecbget(ahb);	/* Always succeeds - no outstanding commands */	ecb->hecb.opcode = ECBOP_READ_HA_INQDATA;	ecb->hecb.flag_word1 = FW1_SUPPRESS_URUN_ERR|FW1_ERR_STATUS_BLK_ONLY;	ecb->hecb.data_ptr = ahb->ha_inq_physbase;	ecb->hecb.data_len = sizeof(struct ha_inquiry_data);	ecb->hecb.sense_ptr = 0;	ecb->state = ECB_ACTIVE;		/* Tell the adapter about this command */	ahbqueuembox(ahb, ahbecbvtop(ahb, ecb),		     ATTN_STARTECB|ahb->scsi_id);	/* Poll for interrupt completion */	for (i = 1000; ecb->state != ECB_FREE && i != 0; i--) {		ahbintr(ahb);		DELAY(1000);	}	ahb->num_ecbs = MIN(ahb->num_ecbs,			    ahb->ha_inq_data->scsi_data.reserved[1]);	printf("ahb%ld: %.8s %s SCSI Adapter, FW Rev. %.4s, ID=%d, %d ECBs\n",	       ahb->unit, ahb->ha_inq_data->scsi_data.product,	       (ahb->ha_inq_data->scsi_data.flags & 0x4) ? "Differential"							 : "Single Ended",	       ahb->ha_inq_data->scsi_data.revision,	       ahb->scsi_id, ahb->num_ecbs);	/* Restore sense paddr for future CCB clients */	ecb->hecb.sense_ptr = ahbsensepaddr(ahbecbvtop(ahb, ecb));	ahbecbfree(ahb, ecb);	/*	 * Create the device queue for our SIM.	 */	devq = cam_simq_alloc(ahb->num_ecbs);	if (devq == NULL)		return (ENOMEM);	/*	 * Construct our SIM entry	 */	ahb->sim = cam_sim_alloc(ahbaction, ahbpoll, "ahb", ahb, ahb->unit,				 2, ahb->num_ecbs, devq);	if (ahb->sim == NULL) {		cam_simq_free(devq);		return (ENOMEM);	}	if (xpt_bus_register(ahb->sim, 0) != CAM_SUCCESS) {		cam_sim_free(ahb->sim, /*free_devq*/TRUE);		return (ENXIO);	}		if (xpt_create_path(&ahb->path, /*periph*/NULL,			    cam_sim_path(ahb->sim), CAM_TARGET_WILDCARD,			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {		xpt_bus_deregister(cam_sim_path(ahb->sim));		cam_sim_free(ahb->sim, /*free_devq*/TRUE);		return (ENXIO);	}			/*	 * Allow the board to generate interrupts.	 */	ahb_outb(ahb, INTDEF, ahb_inb(ahb, INTDEF) | INTEN);	return (0);}static voidahbhandleimmed(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat){	struct ccb_hdr *ccb_h;	u_int target_id;	if (ahb->immed_cmd == 0) {		printf("ahb%ld: Immediate Command complete with no "		       " pending command\n", ahb->unit);		return;	}	target_id = intstat & INTSTAT_TARGET_MASK;	ccb_h = LIST_FIRST(&ahb->pending_ccbs);	while (ccb_h != NULL) {		struct ecb *pending_ecb;		union ccb *ccb;		pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;		ccb = pending_ecb->ccb;		ccb_h = LIST_NEXT(ccb_h, sim_links.le);		if (ccb->ccb_h.target_id == target_id		 || target_id == ahb->scsi_id) {			untimeout(ahbtimeout, pending_ecb,				  ccb->ccb_h.timeout_ch);			LIST_REMOVE(&ccb->ccb_h, sim_links.le);			if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)				bus_dmamap_unload(ahb->buffer_dmat,						  pending_ecb->dmamap);			if (pending_ecb == ahb->immed_ecb)				ccb->ccb_h.status =				    CAM_CMD_TIMEOUT|CAM_RELEASE_SIMQ;			else if (target_id == ahb->scsi_id)				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;			else				ccb->ccb_h.status = CAM_BDR_SENT;			ahbecbfree(ahb, pending_ecb);			xpt_done(ccb);		} else if (ahb->immed_ecb != NULL) {			/* Re-instate timeout */			ccb->ccb_h.timeout_ch =			    timeout(ahbtimeout, (caddr_t)pending_ecb,				    (ccb->ccb_h.timeout * hz) / 1000);		}	}	if (ahb->immed_ecb != NULL) {		ahb->immed_ecb = NULL;		printf("ahb%ld: No longer in timeout\n", ahb->unit);	} else if (target_id == ahb->scsi_id)		printf("ahb%ld: SCSI Bus Reset Delivered\n", ahb->unit);	else		printf("ahb%ld:  Bus Device Reset Delibered to target %d\n",		       ahb->unit, target_id);	ahb->immed_cmd = 0;}static voidahbcalcresid(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb){	if (ecb->status.data_overrun != 0) {		/*		 * Overrun Condition.  The hardware doesn't		 * provide a meaningful byte count in this case		 * (the residual is always 0).  Tell the XPT		 * layer about the error.		 */		ccb->ccb_h.status = CAM_DATA_RUN_ERR;	} else {		ccb->csio.resid = ecb->status.resid_count;		if ((ecb->hecb.flag_word1 & FW1_SG_ECB) != 0) {			/*			 * For S/G transfers, the adapter provides a pointer			 * to the address in the last S/G element used and a			 * residual for that element.  So, we need to sum up			 * the elements that follow it in order to get a real			 * residual number.  If we have an overrun, the residual			 * reported will be 0 and we already know that all S/G			 * segments have been exhausted, so we can skip this			 * step.			 */			ahb_sg_t *sg;			int	  num_sg;			num_sg = ecb->hecb.data_len / sizeof(ahb_sg_t);			/* Find the S/G the adapter was working on */			for (sg = ecb->sg_list;			     num_sg != 0 && sg->addr != ecb->status.resid_addr;			     num_sg--, sg++)				;			/* Skip it */			num_sg--;			sg++;			/* Sum the rest */			for (; num_sg != 0; num_sg--, sg++)				ccb->csio.resid += sg->len;		}		/* Underruns are not errors */		ccb->ccb_h.status = CAM_REQ_CMP;	}}static voidahbprocesserror(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb){	struct hardware_ecb *hecb;	struct ecb_status *status;	hecb = &ecb->hecb;	status = &ecb->status;	switch (status->ha_status) {	case HS_OK:		ccb->csio.scsi_status = status->scsi_status;		if (status->scsi_status != 0) {			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;			if (status->sense_stored) {				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;				ccb->csio.sense_resid =				    ccb->csio.sense_len - status->sense_len;				bcopy(&ecb->sense, &ccb->csio.sense_data,				      status->sense_len);			}		}		break;	case HS_TARGET_NOT_ASSIGNED:		ccb->ccb_h.status = CAM_PATH_INVALID;		break;	case HS_SEL_TIMEOUT:		ccb->ccb_h.status = CAM_SEL_TIMEOUT;		break;	case HS_DATA_RUN_ERR:		ahbcalcresid(ahb, ecb, ccb);		break;	case HS_UNEXPECTED_BUSFREE:		ccb->ccb_h.status = CAM_UNEXP_BUSFREE;		break;	case HS_INVALID_PHASE:		ccb->ccb_h.status = CAM_SEQUENCE_FAIL;		break;	case HS_REQUEST_SENSE_FAILED:		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;		break;	case HS_TAG_MSG_REJECTED:	{		struct ccb_trans_settings neg; 		xpt_print_path(ccb->ccb_h.path);		printf("refuses tagged commands.  Performing "		       "non-tagged I/O\n");		neg.flags = 0;		neg.valid = CCB_TRANS_TQ_VALID;		xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1); 		xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);		ahb->tags_permitted &= ~(0x01 << ccb->ccb_h.target_id);		ccb->ccb_h.status = CAM_MSG_REJECT_REC;		break;	}	case HS_FIRMWARE_LOAD_REQ:	case HS_HARDWARE_ERR:		/*		 * Tell the system that the Adapter		 * is no longer functional.		 */		ccb->ccb_h.status = CAM_NO_HBA;		break;	case HS_CMD_ABORTED_HOST:	case HS_CMD_ABORTED_ADAPTER:	case HS_ATN_TARGET_FAILED:	case HS_SCSI_RESET_ADAPTER:	case HS_SCSI_RESET_INCOMING:		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;		break;	case HS_DUP_TCB_RECEIVED:	case HS_INVALID_OPCODE:	case HS_INVALID_CMD_LINK:	case HS_INVALID_ECB_PARAM:	case HS_PROGRAM_CKSUM_ERROR:		panic("ahb%ld: Can't happen host status %x occurred",		      ahb->unit, status->ha_status);		break;	}	if (ccb->ccb_h.status != CAM_REQ_CMP) {		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);		ccb->ccb_h.status |= CAM_DEV_QFRZN;	}}static voidahbdone(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat){	struct ecb *ecb;	union ccb *ccb;	ecb = ahbecbptov(ahb, mbox);	if ((ecb->state & ECB_ACTIVE) == 0)		panic("ecb not active");	ccb = ecb->ccb;	if (ccb != NULL) {		untimeout(ahbtimeout, ecb, ccb->ccb_h.timeout_ch);		LIST_REMOVE(&ccb->ccb_h, sim_links.le);		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {			bus_dmasync_op_t op;			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)				op = BUS_DMASYNC_POSTREAD;			else				op = BUS_DMASYNC_POSTWRITE;			bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);			bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);		}		if ((intstat & INTSTAT_MASK) == INTSTAT_ECB_OK) {			ccb->ccb_h.status = CAM_REQ_CMP;			ccb->csio.resid = 0;		} else {			ahbprocesserror(ahb, ecb, ccb);		}		ahbecbfree(ahb, ecb);		xpt_done(ccb);	} else {		/* Non CCB Command */		if ((intstat & INTSTAT_MASK) != INTSTAT_ECB_OK) {			printf("ahb%ld: Command 0%x Failed %x:%x:%x\n",			       ahb->unit, ecb->hecb.opcode,			       *((u_int16_t*)&ecb->status),			       ecb->status.ha_status, ecb->status.resid_count);		}		/* Client owns this ECB and will release it. */	}}/* * Catch an interrupt from the adaptor */static voidahbintr(void *arg){	struct	  ahb_softc *ahb;	u_int	  intstat;	u_int32_t mbox;	ahb = (struct ahb_softc *)arg;	while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {		/*		 * Fetch information about this interrupt.		 */		intstat = ahb_inb(ahb, INTSTAT);		mbox = ahb_inl(ahb, MBOXIN0);		/*		 * Reset interrupt latch.		 */		ahb_outb(ahb, CONTROL, CNTRL_CLRINT);		/*		 * Process the completed operation		 */		switch (intstat & INTSTAT_MASK) {		case INTSTAT_ECB_OK:		case INTSTAT_ECB_CMPWRETRY:		case INTSTAT_ECB_CMPWERR:			ahbdone(ahb, mbox, intstat);			break;		case INTSTAT_AEN_OCCURED:			if ((intstat & INTSTAT_TARGET_MASK) == ahb->scsi_id) {				/* Bus Reset */				xpt_print_path(ahb->path);				switch (mbox) {				case HS_SCSI_RESET_ADAPTER:					printf("Host Adapter Initiated "					       "Bus Reset occurred\n");					break;				case HS_SCSI_RESET_INCOMING:					printf("Bus Reset Initiated "					       "by another device occurred\n");					break;				}				/* Notify the XPT */				xpt_async(AC_BUS_RESET, ahb->path, NULL);				break;			}			printf("Unsupported initiator selection AEN occured\n");			break;		case INTSTAT_IMMED_OK:		case INTSTAT_IMMED_ERR:			ahbhandleimmed(ahb, mbox, intstat);			break;		case INTSTAT_HW_ERR:			panic("Unrecoverable hardware Error Occurred\n");		}	}}static voidahbexecuteecb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error){	struct	  ecb *ecb;	union	  ccb *ccb;	struct	  ahb_softc *ahb;	u_int32_t ecb_paddr;	int	  s;	ecb = (struct ecb *)arg;	ccb = ecb->ccb;	ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;	if (error != 0) {		if (error != EFBIG)

⌨️ 快捷键说明

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