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

📄 adwcam.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		adw_eeprom_write(adw, &eep_config);	}	/* Pull eeprom information into our softc. */	adw->bios_ctrl = eep_config.bios_ctrl;	adw->user_wdtr = eep_config.wdtr_able;	adw->user_sdtr = eep_config.sdtr_able;	adw->user_ultra = eep_config.ultra_able;	adw->user_tagenb = eep_config.tagqng_able;	adw->user_discenb = eep_config.disc_enable;	adw->max_acbs = eep_config.max_host_qng;	adw->initiator_id = (eep_config.adapter_scsi_id & ADW_MAX_TID);	/*	 * Sanity check the number of host openings.	 */	if (adw->max_acbs > ADW_DEF_MAX_HOST_QNG)		adw->max_acbs = ADW_DEF_MAX_HOST_QNG;	else if (adw->max_acbs < ADW_DEF_MIN_HOST_QNG) {        	/* If the value is zero, assume it is uninitialized. */		if (adw->max_acbs == 0)			adw->max_acbs = ADW_DEF_MAX_HOST_QNG;		else			adw->max_acbs = ADW_DEF_MIN_HOST_QNG;	}		scsicfg1 = 0;	switch (eep_config.termination) {	default:		printf("%s: Invalid EEPROM Termination Settings.\n",		       adw_name(adw));		printf("%s: Reverting to Automatic Termination\n",		       adw_name(adw));		/* FALLTHROUGH */	case ADW_EEPROM_TERM_AUTO:		break;	case ADW_EEPROM_TERM_BOTH_ON:		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L;		/* FALLTHROUGH */	case ADW_EEPROM_TERM_HIGH_ON:		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H;		/* FALLTHROUGH */	case ADW_EEPROM_TERM_OFF:		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL;		break;	}	printf("%s: SCSI ID %d, ", adw_name(adw), adw->initiator_id);	if (adw_init_chip(adw, scsicfg1) != 0)		return (-1);	printf("Queue Depth %d\n", adw->max_acbs);	/* DMA tag for mapping buffers into device visible space. */	if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/0, /*boundary*/0,			       /*lowaddr*/BUS_SPACE_MAXADDR,			       /*highaddr*/BUS_SPACE_MAXADDR,			       /*filter*/NULL, /*filterarg*/NULL,			       /*maxsize*/MAXBSIZE, /*nsegments*/ADW_SGSIZE,			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,			       /*flags*/BUS_DMA_ALLOCNOW,			       &adw->buffer_dmat) != 0) {		return (-1);	}	adw->init_level++;	/* DMA tag for our ccb structures */	if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/0, /*boundary*/0,			       /*lowaddr*/BUS_SPACE_MAXADDR,			       /*highaddr*/BUS_SPACE_MAXADDR,			       /*filter*/NULL, /*filterarg*/NULL,			       adw->max_acbs * sizeof(struct acb),			       /*nsegments*/1,			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,			       /*flags*/0, &adw->acb_dmat) != 0) {		return (-1);        }	adw->init_level++;	/* Allocation for our ccbs */	if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs,			     BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0) {		return (-1);	}	adw->init_level++;	/* And permanently map them */	bus_dmamap_load(adw->acb_dmat, adw->acb_dmamap,			adw->acbs,			adw->max_acbs * sizeof(struct acb),			adwmapmem, &adw->acb_busbase, /*flags*/0);	/* Clear them out. */	bzero(adw->acbs, adw->max_acbs * sizeof(struct acb)); 	/* DMA tag for our S/G structures.  We allocate in page sized chunks */	if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/0, /*boundary*/0,			       /*lowaddr*/BUS_SPACE_MAXADDR,			       /*highaddr*/BUS_SPACE_MAXADDR,			       /*filter*/NULL, /*filterarg*/NULL,			       PAGE_SIZE, /*nsegments*/1,			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,			       /*flags*/0, &adw->sg_dmat) != 0) {		return (-1);        }	adw->init_level++;	/* Allocate our first batch of ccbs */	if (adwallocacbs(adw) == 0)		return (-1);	return (0);}/* * Attach all the sub-devices we can find */intadw_attach(struct adw_softc *adw){	struct ccb_setasync csa;	struct cam_devq *devq;	/* Start the Risc processor now that we are fully configured. */	adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN);	/*	 * Create the device queue for our SIM.	 */	devq = cam_simq_alloc(adw->max_acbs);	if (devq == NULL)		return (0);	/*	 * Construct our SIM entry.	 */	adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw, adw->unit,				 1, adw->max_acbs, devq);	if (adw->sim == NULL)		return (0);	/*	 * Register the bus.	 */	if (xpt_bus_register(adw->sim, 0) != CAM_SUCCESS) {		cam_sim_free(adw->sim, /*free devq*/TRUE);		return (0);	}	if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim),			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)	   == CAM_REQ_CMP) {		xpt_setup_ccb(&csa.ccb_h, adw->path, /*priority*/5);		csa.ccb_h.func_code = XPT_SASYNC_CB;		csa.event_enable = AC_LOST_DEVICE;		csa.callback = adw_async;		csa.callback_arg = adw;		xpt_action((union ccb *)&csa);	}	return (0);}voidadw_intr(void *arg){	struct	adw_softc *adw;	u_int	int_stat;	u_int	next_doneq;	u_int	next_completeq;	u_int	doneq_start;		adw = (struct adw_softc *)arg;	if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0)		return;	/* Reading the register clears the interrupt. */	int_stat = adw_inb(adw, ADW_INTR_STATUS_REG);	if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) {		/* Idle Command Complete */		adw->idle_command_cmp = 1;		switch (adw->idle_cmd) {		case ADW_IDLE_CMD_DEVICE_RESET:			adw_handle_device_reset(adw,						/*target*/adw->idle_cmd_param);			break;		case ADW_IDLE_CMD_SCSI_RESET:			adw_handle_bus_reset(adw, /*initiated*/TRUE);			break;		default:			break;		}		adw->idle_cmd = ADW_IDLE_CMD_COMPLETED;	}	if ((int_stat & ADW_INTR_STATUS_INTRC) != 0) {		/* SCSI Bus Reset */		adw_handle_bus_reset(adw, /*initiated*/FALSE);        }	/*	 * ADW_MC_HOST_NEXT_DONE is actually the last completed RISC	 * Queue List request. Its forward pointer (RQL_FWD) points to the	 * current completed RISC Queue List request.	 */	next_doneq = adw_lram_read_8(adw, ADW_MC_HOST_NEXT_DONE);	next_doneq = ADW_MC_RISC_Q_LIST_BASE + RQL_FWD		   + (next_doneq * ADW_MC_RISC_Q_LIST_SIZE);	next_completeq = adw_lram_read_8(adw, next_doneq);	doneq_start = ADW_MC_NULL_Q;	/* Loop until all completed Q's are processed. */	while (next_completeq != ADW_MC_NULL_Q) {		u_int32_t acb_busaddr;		struct	  acb *acb;		union	  ccb *ccb;		doneq_start = next_completeq;		next_doneq = ADW_MC_RISC_Q_LIST_BASE +			     (next_completeq * ADW_MC_RISC_Q_LIST_SIZE);		/*		 * Read the ADW_SCSI_REQ_Q physical address pointer from		 * the RISC list entry.		 */		acb_busaddr = adw_lram_read_32(adw, next_doneq + RQL_PHYADDR);		acb = acbptov(adw, acb_busaddr);				/* Change the RISC Queue List state to free. */		adw_lram_write_8(adw, next_doneq + RQL_STATE, ADW_MC_QS_FREE);		/* Get the RISC Queue List forward pointer. */		next_completeq = adw_lram_read_8(adw, next_doneq + RQL_FWD);		/* Process CCB */		ccb = acb->ccb;		untimeout(adwtimeout, acb, ccb->ccb_h.timeout_ch);		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(adw->buffer_dmat, acb->dmamap, op);			bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);			ccb->csio.resid = acb->queue.data_cnt;		} else 			ccb->csio.resid = 0;		/* Common Cases inline... */		if (acb->queue.host_status == QHSTA_NO_ERROR		 && (acb->queue.done_status == QD_NO_ERROR		  || acb->queue.done_status == QD_WITH_ERROR)) {			ccb->csio.scsi_status = acb->queue.scsi_status;			ccb->ccb_h.status = 0;			switch (ccb->csio.scsi_status) {			case SCSI_STATUS_OK:				ccb->ccb_h.status |= CAM_REQ_CMP;				break;			case SCSI_STATUS_CHECK_COND:			case SCSI_STATUS_CMD_TERMINATED:				bcopy(&acb->sense_data, &ccb->csio.sense_data,				      ccb->csio.sense_len);				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;				ccb->csio.sense_resid = acb->queue.sense_len;				/* FALLTHROUGH */			default:				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR						  |  CAM_DEV_QFRZN;				xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);				break;			}			adwfreeacb(adw, acb);			xpt_done(ccb);		} else {			adwprocesserror(adw, acb);		}	}	if (doneq_start != ADW_MC_NULL_Q)		adw_lram_write_8(adw, ADW_MC_HOST_NEXT_DONE, doneq_start);}static voidadwprocesserror(struct adw_softc *adw, struct acb *acb){	union ccb *ccb;	ccb = acb->ccb;	if (acb->queue.done_status == QD_ABORTED_BY_HOST) {		ccb->ccb_h.status = CAM_REQ_ABORTED;	} else {		switch (acb->queue.host_status) {		case QHSTA_M_SEL_TIMEOUT:			ccb->ccb_h.status = CAM_SEL_TIMEOUT;			break;		case QHSTA_M_SXFR_OFF_UFLW:		case QHSTA_M_SXFR_OFF_OFLW:		case QHSTA_M_DATA_OVER_RUN:			ccb->ccb_h.status = CAM_DATA_RUN_ERR;			break;		case QHSTA_M_SXFR_DESELECTED:		case QHSTA_M_UNEXPECTED_BUS_FREE:			ccb->ccb_h.status = CAM_UNEXP_BUSFREE;			break;		case QHSTA_M_QUEUE_ABORTED:			/* BDR or Bus Reset */			ccb->ccb_h.status = adw->last_reset;			break;		case QHSTA_M_SXFR_SDMA_ERR:		case QHSTA_M_SXFR_SXFR_PERR:		case QHSTA_M_RDMA_PERR:			ccb->ccb_h.status = CAM_UNCOR_PARITY;			break;		case QHSTA_M_WTM_TIMEOUT:		case QHSTA_M_SXFR_WD_TMO:			/* The SCSI bus hung in a phase */			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;			adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET,					  /*param*/0);			break;		case QHSTA_M_SXFR_XFR_PH_ERR:			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;			break;		case QHSTA_M_SXFR_UNKNOWN_ERROR:			break;		case QHSTA_M_BAD_CMPL_STATUS_IN:			/* No command complete after a status message */			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;			break;		case QHSTA_M_AUTO_REQ_SENSE_FAIL:			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;			break;		case QHSTA_M_INVALID_DEVICE:			ccb->ccb_h.status = CAM_PATH_INVALID;			break;		case QHSTA_M_NO_AUTO_REQ_SENSE:			/*			 * User didn't request sense, but we got a			 * check condition.			 */			ccb->csio.scsi_status = acb->queue.scsi_status;			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;			break;		default:			panic("%s: Unhandled Host status error %x",			      adw_name(adw), acb->queue.host_status);			/* NOTREACHED */		}	}	if (ccb->ccb_h.status != CAM_REQ_CMP) {		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);		ccb->ccb_h.status |= CAM_DEV_QFRZN;	}	adwfreeacb(adw, acb);	xpt_done(ccb);}static voidadwtimeout(void *arg){	struct acb	     *acb;	union  ccb	     *ccb;	struct adw_softc     *adw;	adw_idle_cmd_status_t status;	int		      s;	acb = (struct acb *)arg;	ccb = acb->ccb;	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;	xpt_print_path(ccb->ccb_h.path);	printf("ACB %p - timed out\n", (void *)acb);	s = splcam();	if ((acb->state & ACB_ACTIVE) == 0) {		xpt_print_path(ccb->ccb_h.path);		printf("ACB %p - timed out CCB already completed\n",		       (void *)acb);		splx(s);		return;	}	/* Attempt a BDR first */	adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,			  ccb->ccb_h.target_id);	splx(s);	status = adw_idle_cmd_wait(adw);	if (status == ADW_IDLE_CMD_SUCCESS) {		printf("%s: BDR Delivered.  No longer in timeout\n",		       adw_name(adw));	} else {		adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET, /*param*/0);		status = adw_idle_cmd_wait(adw);		if (status != ADW_IDLE_CMD_SUCCESS)			panic("%s: Bus Reset during timeout failed",			      adw_name(adw));	}}static voidadw_handle_device_reset(struct adw_softc *adw, u_int target){	struct cam_path *path;	cam_status error;	error = xpt_create_path(&path, /*periph*/NULL, cam_sim_path(adw->sim),				target, CAM_LUN_WILDCARD);	if (error == CAM_REQ_CMP) {		xpt_async(AC_SENT_BDR, path, NULL);		xpt_free_path(path);	}	adw->last_reset = CAM_BDR_SENT;}static voidadw_handle_bus_reset(struct adw_softc *adw, int initiated){	if (initiated) {		/*		 * The microcode currently sets the SCSI Bus Reset signal		 * while handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET		 * command above.  But the SCSI Bus Reset Hold Time in the		 * microcode is not deterministic (it may in fact be for less		 * than the SCSI Spec. minimum of 25 us).  Therefore on return		 * the Adv Library sets the SCSI Bus Reset signal for		 * ADW_SCSI_RESET_HOLD_TIME_US, which is defined to be greater		 * than 25 us.		 */		u_int scsi_ctrl;	    	scsi_ctrl = adw_inw(adw, ADW_SCSI_CTRL) & ~ADW_SCSI_CTRL_RSTOUT;		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl | ADW_SCSI_CTRL_RSTOUT);		DELAY(ADW_SCSI_RESET_HOLD_TIME_US);		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl);		/*		 * We will perform the async notification when the		 * SCSI Reset interrupt occurs.		 */	} else		xpt_async(AC_BUS_RESET, adw->path, NULL);	adw->last_reset = CAM_SCSI_BUS_RESET;}

⌨️ 快捷键说明

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