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

📄 ahb.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			printf("ahb%ld: Unexepected error 0x%x returned from "			       "bus_dmamap_load\n", ahb->unit, error);		if (ccb->ccb_h.status == CAM_REQ_INPROG) {			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;		}		ahbecbfree(ahb, ecb);		xpt_done(ccb);		return;	}			ecb_paddr = ahbecbvtop(ahb, ecb);	if (nseg != 0) {		ahb_sg_t *sg;		bus_dma_segment_t *end_seg;		bus_dmasync_op_t op;		end_seg = dm_segs + nseg;		/* Copy the segments into our SG list */		sg = ecb->sg_list;		while (dm_segs < end_seg) {			sg->addr = dm_segs->ds_addr;			sg->len = dm_segs->ds_len;			sg++;			dm_segs++;		}		if (nseg > 1) {			ecb->hecb.flag_word1 |= FW1_SG_ECB;			ecb->hecb.data_ptr = ahbsgpaddr(ecb_paddr);			ecb->hecb.data_len = sizeof(ahb_sg_t) * nseg;		} else {			ecb->hecb.data_ptr = ecb->sg_list->addr;			ecb->hecb.data_len = ecb->sg_list->len;		}		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {/*			ecb->hecb.flag_word2 |= FW2_DATA_DIR_IN; */			op = BUS_DMASYNC_PREREAD;		} else {			op = BUS_DMASYNC_PREWRITE;		}		/* ecb->hecb.flag_word2 |= FW2_CHECK_DATA_DIR; */		bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);	} else {		ecb->hecb.data_ptr = 0;		ecb->hecb.data_len = 0;	}	s = splcam();	/*	 * Last time we need to check if this CCB needs to	 * be aborted.	 */	if (ccb->ccb_h.status != CAM_REQ_INPROG) {		if (nseg != 0)			bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);		ahbecbfree(ahb, ecb);		xpt_done(ccb);		splx(s);		return;	}			ecb->state = ECB_ACTIVE;	ccb->ccb_h.status |= CAM_SIM_QUEUED;	LIST_INSERT_HEAD(&ahb->pending_ccbs, &ccb->ccb_h, sim_links.le);	/* Tell the adapter about this command */	ahbqueuembox(ahb, ecb_paddr, ATTN_STARTECB|ccb->ccb_h.target_id);	ccb->ccb_h.timeout_ch = timeout(ahbtimeout, (caddr_t)ecb,					(ccb->ccb_h.timeout * hz) / 1000);	splx(s);}static voidahbaction(struct cam_sim *sim, union ccb *ccb){	struct	ahb_softc *ahb;	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahbaction\n"));		ahb = (struct ahb_softc *)cam_sim_softc(sim);		switch (ccb->ccb_h.func_code) {	/* Common cases first */	case XPT_SCSI_IO:	/* Execute the requested I/O operation */	{		struct ecb *ecb;		struct hardware_ecb *hecb;		/*		 * get an ecb to use.		 */		if ((ecb = ahbecbget(ahb)) == NULL) {			/* Should never occur */			panic("Failed to get an ecb");		}		/*		 * So we can find the ECB when an abort is requested		 */		ecb->ccb = ccb;		ccb->ccb_h.ccb_ecb_ptr = ecb;		ccb->ccb_h.ccb_ahb_ptr = ahb;		/*		 * Put all the arguments for the xfer in the ecb		 */		hecb = &ecb->hecb;		hecb->opcode = ECBOP_INITIATOR_SCSI_CMD;		hecb->flag_word1 = FW1_AUTO_REQUEST_SENSE				 | FW1_ERR_STATUS_BLK_ONLY;		hecb->flag_word2 = ccb->ccb_h.target_lun				 | FW2_NO_RETRY_ON_BUSY;		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {			hecb->flag_word2 |= FW2_TAG_ENB					 | ((ccb->csio.tag_action & 0x3)					    << FW2_TAG_TYPE_SHIFT);		}		if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)			hecb->flag_word2 |= FW2_DISABLE_DISC;		hecb->sense_len = ccb->csio.sense_len;		hecb->cdb_len = ccb->csio.cdb_len;		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {				bcopy(ccb->csio.cdb_io.cdb_ptr,				      hecb->cdb, hecb->cdb_len);			} else {				/* I guess I could map it in... */				ccb->ccb_h.status = CAM_REQ_INVALID;				ahbecbfree(ahb, ecb);				xpt_done(ccb);				return;			}		} else {			bcopy(ccb->csio.cdb_io.cdb_bytes,			      hecb->cdb, hecb->cdb_len);		}		/*		 * If we have any data to send with this command,		 * map it into bus space.		 */		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {			if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) {				/*				 * We've been given a pointer				 * to a single buffer.				 */				if ((ccb->ccb_h.flags & CAM_DATA_PHYS)==0) {					int s;					int error;					s = splsoftvm();					error = bus_dmamap_load(					    ahb->buffer_dmat,					    ecb->dmamap,					    ccb->csio.data_ptr,					    ccb->csio.dxfer_len,					    ahbexecuteecb,					    ecb, /*flags*/0);					if (error == EINPROGRESS) {						/*						 * So as to maintain ordering,						 * freeze the controller queue						 * until our mapping is						 * returned.						 */						xpt_freeze_simq(ahb->sim, 1);						ccb->ccb_h.status |=						    CAM_RELEASE_SIMQ;					}					splx(s);				} else {					struct bus_dma_segment seg; 					/* Pointer to physical buffer */					seg.ds_addr =					    (bus_addr_t)ccb->csio.data_ptr;					seg.ds_len = ccb->csio.dxfer_len;					ahbexecuteecb(ecb, &seg, 1, 0);				}			} else {				struct bus_dma_segment *segs;				if ((ccb->ccb_h.flags & CAM_DATA_PHYS) != 0)					panic("ahbaction - Physical segment "					      "pointers unsupported");				if ((ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0)					panic("btaction - Virtual segment "					      "addresses unsupported");				/* Just use the segments provided */				segs = (struct bus_dma_segment *)				    ccb->csio.data_ptr;				ahbexecuteecb(ecb, segs, ccb->csio.sglist_cnt,					     0);			}		} else {			ahbexecuteecb(ecb, NULL, 0, 0);		}		break;	}	case XPT_EN_LUN:		/* Enable LUN as a target */	case XPT_TARGET_IO:		/* Execute target I/O request */	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/	case XPT_ABORT:			/* Abort the specified CCB */		/* XXX Implement */		ccb->ccb_h.status = CAM_REQ_INVALID;		xpt_done(ccb);		break;	case XPT_SET_TRAN_SETTINGS:	{		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;		xpt_done(ccb);		break;	}	case XPT_GET_TRAN_SETTINGS:	/* Get default/user set transfer settings for the target */	{		struct	ccb_trans_settings *cts;		u_int	target_mask;		cts = &ccb->cts;		target_mask = 0x01 << ccb->ccb_h.target_id;		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {			cts->flags = 0;			if ((ahb->disc_permitted & target_mask) != 0)				cts->flags |= CCB_TRANS_DISC_ENB;			if ((ahb->tags_permitted & target_mask) != 0)				cts->flags |= CCB_TRANS_TAG_ENB;			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;			cts->sync_period = 25; /* 10MHz */			if (cts->sync_period != 0)				cts->sync_offset = 15;			cts->valid = CCB_TRANS_SYNC_RATE_VALID				   | CCB_TRANS_SYNC_OFFSET_VALID				   | CCB_TRANS_BUS_WIDTH_VALID				   | CCB_TRANS_DISC_VALID				   | CCB_TRANS_TQ_VALID;			ccb->ccb_h.status = CAM_REQ_CMP;		} else {			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;		}		xpt_done(ccb);		break;	}	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */	{		int i;		int s;		s = splcam();		ahb->immed_cmd = IMMED_RESET;		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);		/* Poll for interrupt completion */		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--) {			DELAY(1000);			ahbintr(cam_sim_softc(sim));		}		splx(s);		break;	}	case XPT_CALC_GEOMETRY:	{		struct	  ccb_calc_geometry *ccg;		u_int32_t size_mb;		u_int32_t secs_per_cylinder;		ccg = &ccb->ccg;		size_mb = ccg->volume_size			/ ((1024L * 1024L) / ccg->block_size);				if (size_mb > 1024 && (ahb->extended_trans != 0)) {			ccg->heads = 255;			ccg->secs_per_track = 63;		} else {			ccg->heads = 64;			ccg->secs_per_track = 32;		}		secs_per_cylinder = ccg->heads * ccg->secs_per_track;		ccg->cylinders = ccg->volume_size / secs_per_cylinder;		ccb->ccb_h.status = CAM_REQ_CMP;		xpt_done(ccb);		break;	}	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */	{		int i;		ahb->immed_cmd = IMMED_RESET;		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);		/* Poll for interrupt completion */		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--)			DELAY(1000);		ccb->ccb_h.status = CAM_REQ_CMP;		xpt_done(ccb);		break;	}	case XPT_TERM_IO:		/* Terminate the I/O process */		/* XXX Implement */		ccb->ccb_h.status = CAM_REQ_INVALID;		xpt_done(ccb);		break;	case XPT_PATH_INQ:		/* Path routing inquiry */	{		struct ccb_pathinq *cpi = &ccb->cpi;				cpi->version_num = 1; /* XXX??? */		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;		cpi->target_sprt = 0;		cpi->hba_misc = 0;		cpi->hba_eng_cnt = 0;		cpi->max_target = 7;		cpi->max_lun = 7;		cpi->initiator_id = ahb->scsi_id;		cpi->bus_id = cam_sim_bus(sim);		cpi->base_transfer_speed = 3300;		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);		cpi->unit_number = cam_sim_unit(sim);		cpi->ccb_h.status = CAM_REQ_CMP;		xpt_done(ccb);		break;	}#if 0	/* Need these??? */        case XPT_IMMED_NOTIFY:		/* Notify Host Target driver of event */        case XPT_NOTIFY_ACK:		/* Acknowledgement of event */#endif	default:		ccb->ccb_h.status = CAM_REQ_INVALID;		xpt_done(ccb);		break;	}}static voidahbpoll(struct cam_sim *sim){	ahbintr(cam_sim_softc(sim));}voidahbtimeout(void *arg){	struct ecb	 *ecb;	union  ccb	 *ccb;	struct ahb_softc *ahb;	int		  s;	ecb = (struct ecb *)arg;	ccb = ecb->ccb;	ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;	xpt_print_path(ccb->ccb_h.path);	printf("ECB %p - timed out\n", (void *)ecb);	s = splcam();	if ((ecb->state & ECB_ACTIVE) == 0) {		xpt_print_path(ccb->ccb_h.path);		printf("ECB %p - timed out ECB already completed\n",		       (void *)ecb);		splx(s);		return;	}	/*	 * In order to simplify the recovery process, we ask the XPT	 * layer to halt the queue of new transactions and we traverse	 * the list of pending CCBs and remove their timeouts. This	 * means that the driver attempts to clear only one error	 * condition at a time.  In general, timeouts that occur	 * close together are related anyway, so there is no benefit	 * in attempting to handle errors in parrallel.  Timeouts will	 * be reinstated when the recovery process ends.	 */	if ((ecb->state & ECB_DEVICE_RESET) == 0) {		struct ccb_hdr *ccb_h;		if ((ecb->state & ECB_RELEASE_SIMQ) == 0) {			xpt_freeze_simq(ahb->sim, /*count*/1);			ecb->state |= ECB_RELEASE_SIMQ;		}		ccb_h = LIST_FIRST(&ahb->pending_ccbs);		while (ccb_h != NULL) {			struct ecb *pending_ecb;			pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;			untimeout(ahbtimeout, pending_ecb, ccb_h->timeout_ch);			ccb_h = LIST_NEXT(ccb_h, sim_links.le);		}		/* Store for our interrupt handler */		ahb->immed_ecb = ecb;		/*    		 * Send a Bus Device Reset message:		 * The target that is holding up the bus may not		 * be the same as the one that triggered this timeout		 * (different commands have different timeout lengths),		 * but we have no way of determining this from our		 * timeout handler.  Our strategy here is to queue a		 * BDR message to the target of the timed out command.		 * If this fails, we'll get another timeout 2 seconds		 * later which will attempt a bus reset.		 */		xpt_print_path(ccb->ccb_h.path);		printf("Queuing BDR\n");		ecb->state |= ECB_DEVICE_RESET;		ccb->ccb_h.timeout_ch =		    timeout(ahbtimeout, (caddr_t)ecb, 2 * hz);		ahb->immed_cmd = IMMED_RESET;		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);	} else if ((ecb->state & ECB_SCSIBUS_RESET) != 0) {		/*		 * Try a SCSI bus reset.  We do this only if we		 * have already attempted to clear the condition with a BDR.		 */		xpt_print_path(ccb->ccb_h.path);		printf("Attempting SCSI Bus reset\n");		ecb->state |= ECB_SCSIBUS_RESET;		ccb->ccb_h.timeout_ch =		    timeout(ahbtimeout, (caddr_t)ecb, 2 * hz);		ahb->immed_cmd = IMMED_RESET;		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);	} else {		/* Bring out the hammer... */		ahbreset(ahb);		/* Simulate the reset complete interrupt */		ahbhandleimmed(ahb, 0, ahb->scsi_id|INTSTAT_IMMED_OK);	}	splx(s);}#endif /* NEISA */

⌨️ 快捷键说明

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