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

📄 advansys.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 * Currently, the output of bus_dmammap_load suits our needs just * fine, but should it change, we'd need to do something here. */#define adv_fixup_dmasegs(adv, dm_segs) (struct adv_sg_entry *)(dm_segs)static voidadv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs,		int nsegments, int error){	struct	ccb_scsiio *csio;	struct	ccb_hdr *ccb_h;	struct	cam_sim *sim;        struct	adv_softc *adv;	struct	adv_ccb_info *cinfo;	struct	adv_scsi_q scsiq;	struct	adv_sg_head sghead;	int	s;	csio = (struct ccb_scsiio *)arg;	ccb_h = &csio->ccb_h;	sim = xpt_path_sim(ccb_h->path);	adv = (struct adv_softc *)cam_sim_softc(sim);	cinfo = (struct adv_ccb_info *)csio->ccb_h.ccb_cinfo_ptr;	if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {		if ((ccb_h->flags & CAM_CDB_PHYS) == 0) {			/* XXX Need phystovirt!!!! */			/* How about pmap_kenter??? */			scsiq.cdbptr = csio->cdb_io.cdb_ptr;		} else {			scsiq.cdbptr = csio->cdb_io.cdb_ptr;		}	} else {		scsiq.cdbptr = csio->cdb_io.cdb_bytes;	}	/*	 * Build up the request	 */	scsiq.q1.status = 0;	scsiq.q1.q_no = 0;	scsiq.q1.cntl = 0;	scsiq.q1.sg_queue_cnt = 0;	scsiq.q1.target_id = ADV_TID_TO_TARGET_MASK(ccb_h->target_id);	scsiq.q1.target_lun = ccb_h->target_lun;	scsiq.q1.sense_len = csio->sense_len;	scsiq.q1.extra_bytes = 0;	scsiq.q2.ccb_ptr = (u_int32_t)csio;	scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(ccb_h->target_id,					      ccb_h->target_lun);	scsiq.q2.flag = 0;	scsiq.q2.cdb_len = csio->cdb_len;	if ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0)		scsiq.q2.tag_code = csio->tag_action;	else		scsiq.q2.tag_code = 0;	scsiq.q2.vm_id = 0;	if (nsegments != 0) {		bus_dmasync_op_t op;		scsiq.q1.data_addr = dm_segs->ds_addr;                scsiq.q1.data_cnt = dm_segs->ds_len;		if (nsegments > 1) {			scsiq.q1.cntl |= QC_SG_HEAD;			sghead.entry_cnt			    = sghead.entry_to_copy			    = nsegments;			sghead.res = 0;			sghead.sg_list = adv_fixup_dmasegs(adv, dm_segs);			scsiq.sg_head = &sghead;		} else {			scsiq.sg_head = NULL;		}		if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN)			op = BUS_DMASYNC_PREREAD;		else			op = BUS_DMASYNC_PREWRITE;		bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);	} else {		scsiq.q1.data_addr = 0;			scsiq.q1.data_cnt = 0;		scsiq.sg_head = NULL;	}	s = splcam();	/*	 * Last time we need to check if this SCB needs to	 * be aborted.	 */             	if (ccb_h->status != CAM_REQ_INPROG) {		if (nsegments != 0) {			bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);		}		if ((cinfo->state & ACCB_RELEASE_SIMQ) != 0) {			ccb_h->status |= CAM_RELEASE_SIMQ;		}		adv_free_ccb_info(adv, cinfo);		xpt_done((union ccb *)csio);		splx(s);		return;	}	if (adv_execute_scsi_queue(adv, &scsiq, csio->dxfer_len) != 0) {		/* Temporary resource shortage */		if (nsegments != 0) {			bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);		}		ccb_h->status = CAM_REQUEUE_REQ;		if ((cinfo->state & ACCB_RELEASE_SIMQ) != 0)			ccb_h->status |= CAM_RELEASE_SIMQ;		/* Unfreeze when resources are available */		xpt_freeze_simq(adv->sim, /*count*/1);		adv_free_ccb_info(adv, cinfo);		xpt_done((union ccb *)csio);		splx(s);		return;	}	cinfo->state |= ACCB_ACTIVE;	ccb_h->status |= CAM_SIM_QUEUED;	LIST_INSERT_HEAD(&adv->pending_ccbs, ccb_h, sim_links.le);	/* Schedule our timeout */	ccb_h->timeout_ch =	    timeout(adv_timeout, csio, (ccb_h->timeout * hz)/1000);	splx(s);}static struct adv_ccb_info *adv_alloc_ccb_info(struct adv_softc *adv){	int error;	struct adv_ccb_info *cinfo;	cinfo = malloc(sizeof(*cinfo), M_DEVBUF, M_NOWAIT);	if (cinfo == NULL) {		printf("%s: Can't malloc CCB info\n", adv_name(adv));		return (NULL);	}	cinfo->state = ACCB_FREE;	error = bus_dmamap_create(adv->buffer_dmat, /*flags*/0,				  &cinfo->dmamap);	if (error != 0) {		printf("%s: Unable to allocate CCB info "		       "dmamap - error %d\n", adv_name(adv), error);		free(cinfo, M_DEVBUF);		cinfo = NULL;	}	return (cinfo);}static voidadv_destroy_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo){	bus_dmamap_destroy(adv->buffer_dmat, cinfo->dmamap);	free(cinfo, M_DEVBUF);}voidadv_timeout(void *arg){	int s;	union ccb *ccb;	struct adv_softc *adv;	struct adv_ccb_info *cinfo;	ccb = (union ccb *)arg;	adv = (struct adv_softc *)xpt_path_sim(ccb->ccb_h.path)->softc;	cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;	xpt_print_path(ccb->ccb_h.path);	printf("Timed out\n");	s = splcam();	/* Have we been taken care of already?? */	if (cinfo == NULL || cinfo->state == ACCB_FREE) {		splx(s);		return;	}	adv_stop_execution(adv);	if ((cinfo->state & ACCB_ABORT_QUEUED) == 0) {		struct ccb_hdr *ccb_h;		/*		 * 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 ((cinfo->state & ACCB_RELEASE_SIMQ) == 0) {			xpt_freeze_simq(adv->sim, /*count*/1);			cinfo->state |= ACCB_RELEASE_SIMQ;		}		/* This CCB is the CCB representing our recovery actions */		cinfo->state |= ACCB_RECOVERY_CCB|ACCB_ABORT_QUEUED;		ccb_h = LIST_FIRST(&adv->pending_ccbs);		while (ccb_h != NULL) {			untimeout(adv_timeout, ccb_h, ccb_h->timeout_ch);			ccb_h = LIST_NEXT(ccb_h, sim_links.le);		}		/* XXX Should send a BDR */		/* Attempt an abort as our first tact */		xpt_print_path(ccb->ccb_h.path);		printf("Attempting abort\n");		adv_abort_ccb(adv, ccb->ccb_h.target_id,			      ccb->ccb_h.target_lun, ccb,			      CAM_CMD_TIMEOUT, /*queued_only*/FALSE);		ccb->ccb_h.timeout_ch =		    timeout(adv_timeout, ccb, 2 * hz);	} else {		/* Our attempt to perform an abort failed, go for a reset */		xpt_print_path(ccb->ccb_h.path);		printf("Resetting bus\n");				ccb->ccb_h.status &= ~CAM_STATUS_MASK;		ccb->ccb_h.status |= CAM_CMD_TIMEOUT;		adv_reset_bus(adv);	}	adv_start_execution(adv);	splx(s);}struct adv_softc *adv_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh){	struct	 adv_softc *adv;   	if (unit >= NADV) {		printf("adv: unit number (%d) too high\n", unit);		return NULL;	}	/*	 * Allocate a storage area for us	 */	if (advsoftcs[unit]) {		printf("adv%d: memory already allocated\n", unit);		return NULL;	}	adv = malloc(sizeof(struct adv_softc), M_DEVBUF, M_NOWAIT);	if (!adv) {		printf("adv%d: cannot malloc!\n", unit);		return NULL;	}	bzero(adv, sizeof(struct adv_softc));	LIST_INIT(&adv->pending_ccbs);	SLIST_INIT(&adv->free_ccb_infos);	advsoftcs[unit] = adv;	adv->unit = unit;	adv->tag = tag;	adv->bsh = bsh;	return(adv);}voidadv_free(struct adv_softc *adv){	switch (adv->init_level) {	case 5:	{		struct adv_ccb_info *cinfo;		while ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) {			SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links);			adv_destroy_ccb_info(adv, cinfo);			}				bus_dmamap_unload(adv->sense_dmat, adv->sense_dmamap);	}	case 4:		bus_dmamem_free(adv->sense_dmat, adv->sense_buffers,                                adv->sense_dmamap);	case 3:		bus_dma_tag_destroy(adv->sense_dmat);	case 2:		bus_dma_tag_destroy(adv->buffer_dmat);	case 1:		bus_dma_tag_destroy(adv->parent_dmat);	case 0:		break;	}	free(adv, M_DEVBUF);}intadv_init(struct adv_softc *adv){	struct	  adv_eeprom_config eeprom_config;	int	  checksum, i;	u_int16_t config_lsw;	u_int16_t config_msw;	adv_reset_chip_and_scsi_bus(adv);	adv_lib_init(adv);        /*         * Stop script execution.         */          adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE);        adv_stop_execution(adv);	if (adv_is_chip_halted(adv) == 0) {		printf("adv%d: Unable to halt adapter. Initialization"		       "failed\n", adv->unit);		return (1);	}	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);	if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {		printf("adv%d: Unable to set program counter. Initialization"		       "failed\n", adv->unit);		return (1);	}	config_msw = ADV_INW(adv, ADV_CONFIG_MSW);	config_lsw = ADV_INW(adv, ADV_CONFIG_LSW);	if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) {		config_msw &= (~(ADV_CFG_MSW_CLR_MASK));		/*		 * XXX The Linux code flags this as an error,		 * but what should we report to the user???		 * It seems that clearing the config register		 * makes this error recoverable.		 */		ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);	}	/* Suck in the configuration from the EEProm */	checksum = adv_get_eeprom_config(adv, &eeprom_config);	eeprom_config.cfg_msw &= (~(ADV_CFG_MSW_CLR_MASK));	if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) {		/*		 * XXX The Linux code sets a warning level for this		 * condition, yet nothing of meaning is printed to		 * the user.  What does this mean???		 */		if (adv->chip_version == 3) {			if (eeprom_config.cfg_lsw != config_lsw) {				eeprom_config.cfg_lsw =						ADV_INW(adv, ADV_CONFIG_LSW);			}			if (eeprom_config.cfg_msw != config_msw) {				eeprom_config.cfg_msw =						ADV_INW(adv, ADV_CONFIG_MSW);			}		}	}	eeprom_config.cfg_lsw |= ADV_CFG_LSW_HOST_INT_ON;	if (adv_test_external_lram(adv) == 0) {		/*		 * XXX What about non PCI cards with no		 *     external LRAM????		 */		if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)) {			eeprom_config.max_total_qng =			    ADV_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;			eeprom_config.max_tag_qng =			    ADV_MAX_PCI_ULTRA_INRAM_TAG_QNG;		} else {			eeprom_config.cfg_msw |= 0x0800;			config_msw |= 0x0800;			ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);			eeprom_config.max_total_qng =			     ADV_MAX_PCI_INRAM_TOTAL_QNG;			eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG;		}		adv->max_openings = eeprom_config.max_total_qng;	}	if (checksum == eeprom_config.chksum) {		/* Range/Sanity checking */		if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) {			eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG;		}		if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) {			eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG;		}		if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) {			eeprom_config.max_tag_qng = eeprom_config.max_total_qng;		}		if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) {			eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC;		}		adv->max_openings = eeprom_config.max_total_qng;		adv->user_disc_enable = eeprom_config.disc_enable;		adv->user_cmd_qng_enabled = eeprom_config.use_cmd_qng;		adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config);		adv->scsi_id = EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID;		EEPROM_SET_SCSIID(eeprom_config, adv->scsi_id);		adv->control = eeprom_config.cntl;		for (i = 0; i <= ADV_MAX_TID; i++)			adv_sdtr_to_period_offset(adv,						  eeprom_config.sdtr_data[i],						  &adv->tinfo[i].user.period,						  &adv->tinfo[i].user.offset,						  i);	} else {		u_int8_t sync_data;		printf("adv%d: Warning EEPROM Checksum mismatch. "		       "Using default device parameters\n", adv->unit);		/* Set reasonable defaults since we can't read the EEPROM */		adv->isa_dma_speed = /*ADV_DEF_ISA_DMA_SPEED*/1;		adv->max_openings = ADV_DEF_MAX_TOTAL_QNG;		adv->disc_enable = TARGET_BIT_VECTOR_SET;		adv->user_disc_enable = TARGET_BIT_VECTOR_SET;		adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET;		adv->user_cmd_qng_enabled = TARGET_BIT_VECTOR_SET;		adv->scsi_id = 7;		sync_data = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4);		for (i = 0; i <= ADV_MAX_TID; i++)			adv_sdtr_to_period_offset(adv, sync_data,						  &adv->tinfo[i].user.period,						  &adv->tinfo[i].user.offset,						  i);	}	if (adv_set_eeprom_config(adv, &eeprom_config) != 0)		printf("%s: WARNING! Failure writing to EEPROM.\n",		       adv_name(adv));	adv_set_chip_scsiid(adv, adv->scsi_id);	if (adv_init_lram_and_mcode(adv))		return (1);	adv->disc_enable = adv->user_disc_enable;	adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable); 	for (i = 0; i <= ADV_MAX_TID; i++) {		/*		 * Start off in async mode.		 */		adv_set_syncrate(adv, /*struct cam_path */NULL,				 i, /*period*/0, /*offset*/0,				 ADV_TRANS_CUR);		/*		 * Enable the use of tagged commands on all targets.

⌨️ 快捷键说明

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