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

📄 adwcam.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * CAM SCSI interface for the the Advanced Systems Inc. * Second Generation SCSI controllers. * * Product specific probe and attach routines can be found in: *  * pci/adw_pci.c	ABP940UW * * Copyright (c) 1998 Justin Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions, and the following disclaimer, *    without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *      $Id: adwcam.c,v 1.2.2.1 1999/05/07 00:43:22 ken Exp $ *//* * Ported from: * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters *      * Copyright (c) 1995-1998 Advanced System Products, Inc. * All Rights Reserved. *    * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that redistributions of source * code retain the above copyright notice and this comment without * modification. */#include <stddef.h>	/* For offsetof */#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/malloc.h>#include <machine/bus_pio.h>#include <machine/bus_memio.h>#include <machine/bus.h>#include <machine/clock.h>#include <cam/cam.h>#include <cam/cam_ccb.h>#include <cam/cam_sim.h>#include <cam/cam_xpt_sim.h>#include <cam/cam_debug.h>#include <cam/scsi/scsi_message.h>#include <dev/advansys/adwvar.h>/* Definitions for our use of the SIM private CCB area */#define ccb_acb_ptr spriv_ptr0#define ccb_adw_ptr spriv_ptr1#define MIN(a, b) (((a) < (b)) ? (a) : (b))u_long adw_unit;static __inline u_int32_t	acbvtop(struct adw_softc *adw,					   struct acb *acb);static __inline struct acb *	acbptov(struct adw_softc *adw,					u_int32_t busaddr);static __inline struct acb*	adwgetacb(struct adw_softc *adw);static __inline void		adwfreeacb(struct adw_softc *adw,					   struct acb *acb);static void		adwmapmem(void *arg, bus_dma_segment_t *segs,				  int nseg, int error);static struct sg_map_node*			adwallocsgmap(struct adw_softc *adw);static int		adwallocacbs(struct adw_softc *adw);static void		adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs,				      int nseg, int error);static void		adw_action(struct cam_sim *sim, union ccb *ccb);static void		adw_poll(struct cam_sim *sim);static void		adw_async(void *callback_arg, u_int32_t code,				  struct cam_path *path, void *arg);static void		adwprocesserror(struct adw_softc *adw, struct acb *acb);static void		adwtimeout(void *arg);static void		adw_handle_device_reset(struct adw_softc *adw,						u_int target);static void		adw_handle_bus_reset(struct adw_softc *adw,					     int initiated);static __inline u_int32_tacbvtop(struct adw_softc *adw, struct acb *acb){	return (adw->acb_busbase	      + (u_int32_t)((caddr_t)acb - (caddr_t)adw->acbs));}static __inline struct acb *acbptov(struct adw_softc *adw, u_int32_t busaddr){	return (adw->acbs	      + ((struct acb *)busaddr - (struct acb *)adw->acb_busbase));}static __inline struct acb*adwgetacb(struct adw_softc *adw){	struct	acb* acb;	int	s;	s = splcam();	if ((acb = SLIST_FIRST(&adw->free_acb_list)) != NULL) {		SLIST_REMOVE_HEAD(&adw->free_acb_list, links);	} else if (adw->num_acbs < adw->max_acbs) {		adwallocacbs(adw);		acb = SLIST_FIRST(&adw->free_acb_list);		if (acb == NULL)			printf("%s: Can't malloc ACB\n", adw_name(adw));		else {			SLIST_REMOVE_HEAD(&adw->free_acb_list, links);		}	}	splx(s);	return (acb);}static __inline voidadwfreeacb(struct adw_softc *adw, struct acb *acb){	int s;	s = splcam();	if ((acb->state & ACB_ACTIVE) != 0)		LIST_REMOVE(&acb->ccb->ccb_h, sim_links.le);	if ((acb->state & ACB_RELEASE_SIMQ) != 0)		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;	else if ((adw->state & ADW_RESOURCE_SHORTAGE) != 0	      && (acb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;		adw->state &= ~ADW_RESOURCE_SHORTAGE;	}	acb->state = ACB_FREE;	SLIST_INSERT_HEAD(&adw->free_acb_list, acb, links);	splx(s);}static voidadwmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error){	bus_addr_t *busaddrp;	busaddrp = (bus_addr_t *)arg;	*busaddrp = segs->ds_addr;}static struct sg_map_node *adwallocsgmap(struct adw_softc *adw){	struct sg_map_node *sg_map;	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);	if (sg_map == NULL)		return (NULL);	/* Allocate S/G space for the next batch of ACBS */	if (bus_dmamem_alloc(adw->sg_dmat, (void **)&sg_map->sg_vaddr,			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {		free(sg_map, M_DEVBUF);		return (NULL);	}	SLIST_INSERT_HEAD(&adw->sg_maps, sg_map, links);	bus_dmamap_load(adw->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,			PAGE_SIZE, adwmapmem, &sg_map->sg_physaddr, /*flags*/0);	bzero(sg_map->sg_vaddr, PAGE_SIZE);	return (sg_map);}/* * Allocate another chunk of CCB's. Return count of entries added. * Assumed to be called at splcam(). */static intadwallocacbs(struct adw_softc *adw){	struct acb *next_acb;	struct sg_map_node *sg_map;	bus_addr_t busaddr;	struct adw_sg_block *blocks;	int newcount;	int i;	next_acb = &adw->acbs[adw->num_acbs];	sg_map = adwallocsgmap(adw);	if (sg_map == NULL)		return (0);	blocks = sg_map->sg_vaddr;	busaddr = sg_map->sg_physaddr;	newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks)));	for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) {		int error;		int j;		error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0,					  &next_acb->dmamap);		if (error != 0)			break;		next_acb->queue.scsi_req_baddr = acbvtop(adw, next_acb);		next_acb->queue.sense_addr =		    acbvtop(adw, next_acb) + offsetof(struct acb, sense_data);		next_acb->sg_blocks = blocks;		next_acb->sg_busaddr = busaddr;		/* Setup static data in the sg blocks */		for (j = 0; j < ADW_SG_BLOCKCNT; j++) {			next_acb->sg_blocks[j].first_entry_no =			    j * ADW_NO_OF_SG_PER_BLOCK;		}		next_acb->state = ACB_FREE;		SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links);		blocks += ADW_SG_BLOCKCNT;		busaddr += ADW_SG_BLOCKCNT * sizeof(*blocks);		next_acb++;		adw->num_acbs++;	}	return (i);}static voidadwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error){	struct	 acb *acb;	union	 ccb *ccb;	struct	 adw_softc *adw;	int	 s;	acb = (struct acb *)arg;	ccb = acb->ccb;	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;	if (error != 0) {		if (error != EFBIG)			printf("%s: Unexepected error 0x%x returned from "			       "bus_dmamap_load\n", adw_name(adw), 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;		}		adwfreeacb(adw, acb);		xpt_done(ccb);		return;	}			if (nseg != 0) {		bus_dmasync_op_t op;		acb->queue.data_addr = dm_segs[0].ds_addr;		acb->queue.data_cnt = ccb->csio.dxfer_len;		if (nseg > 1) {			struct adw_sg_block *sg_block;			struct adw_sg_elm *sg;			bus_addr_t sg_busaddr;			u_int sg_index;			bus_dma_segment_t *end_seg;			end_seg = dm_segs + nseg;			sg_busaddr = acb->sg_busaddr;			sg_index = 0;			/* Copy the segments into our SG list */			for (sg_block = acb->sg_blocks;; sg_block++) {				u_int sg_left;				sg_left = ADW_NO_OF_SG_PER_BLOCK;				sg = sg_block->sg_list;				while (dm_segs < end_seg && sg_left != 0) {					sg->sg_addr = dm_segs->ds_addr;					sg->sg_count = dm_segs->ds_len;					sg++;					dm_segs++;					sg_left--;				}				sg_index += ADW_NO_OF_SG_PER_BLOCK - sg_left;				sg_block->last_entry_no = sg_index - 1;				if (dm_segs == end_seg) {					sg_block->sg_busaddr_next = 0;					break;				} else {					sg_busaddr +=					    sizeof(struct adw_sg_block);					sg_block->sg_busaddr_next = sg_busaddr;				}			}			acb->queue.sg_entry_cnt = nseg;			acb->queue.sg_real_addr = acb->sg_busaddr;		} else {			acb->queue.sg_entry_cnt = 0;			acb->queue.sg_real_addr = 0;		}		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)			op = BUS_DMASYNC_PREREAD;		else			op = BUS_DMASYNC_PREWRITE;		bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);	} else {		acb->queue.sg_entry_cnt = 0;		acb->queue.data_addr = 0;		acb->queue.data_cnt = 0;		acb->queue.sg_real_addr = 0;	}	acb->queue.free_scsiq_link = 0;	acb->queue.ux_wk_data_cnt = 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(adw->buffer_dmat, acb->dmamap);		adwfreeacb(adw, acb);		xpt_done(ccb);		splx(s);		return;	}			acb->state |= ACB_ACTIVE;	ccb->ccb_h.status |= CAM_SIM_QUEUED;	LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le);	ccb->ccb_h.timeout_ch =	    timeout(adwtimeout, (caddr_t)acb,		    (ccb->ccb_h.timeout * hz) / 1000);	adw_send_acb(adw, acb, acbvtop(adw, acb));	splx(s);}static voidadw_action(struct cam_sim *sim, union ccb *ccb){	struct	adw_softc *adw;	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adw_action\n"));		adw = (struct adw_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	ccb_scsiio *csio;		struct	ccb_hdr *ccbh;		struct	acb *acb;		csio = &ccb->csio;		ccbh = &ccb->ccb_h;		/* Max supported CDB length is 12 bytes */		if (csio->cdb_len > 12) { 			ccb->ccb_h.status = CAM_REQ_INVALID;			xpt_done(ccb);			return;		}		if ((acb = adwgetacb(adw)) == NULL) {			int s;				s = splcam();			adw->state |= ADW_RESOURCE_SHORTAGE;			splx(s);			xpt_freeze_simq(sim, /*count*/1);			ccb->ccb_h.status = CAM_REQUEUE_REQ;			xpt_done(ccb);			return;		}		/* Link dccb and ccb so we can find one from the other */		acb->ccb = ccb;		ccb->ccb_h.ccb_acb_ptr = acb;		ccb->ccb_h.ccb_adw_ptr = adw;		acb->queue.cntl = 0;		acb->queue.target_id = ccb->ccb_h.target_id;		acb->queue.target_lun = ccb->ccb_h.target_lun;		acb->queue.srb_ptr = 0;		acb->queue.a_flag = 0;		acb->queue.sense_len =			MIN(csio->sense_len, sizeof(acb->sense_data));		acb->queue.cdb_len = csio->cdb_len;		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0)			acb->queue.tag_code = csio->tag_action;		else			acb->queue.tag_code = 0;		acb->queue.done_status = 0;		acb->queue.scsi_status = 0;		acb->queue.host_status = 0;		acb->queue.ux_sg_ix = 0;		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {				bcopy(csio->cdb_io.cdb_ptr,				      acb->queue.cdb, csio->cdb_len);			} else {				/* I guess I could map it in... */				ccb->ccb_h.status = CAM_REQ_INVALID;				adwfreeacb(adw, acb);				xpt_done(ccb);				return;			}		} else {			bcopy(csio->cdb_io.cdb_bytes,			      acb->queue.cdb, csio->cdb_len);		}		/*		 * If we have any data to send with this command,		 * map it into bus space.		 */		if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {			if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {				/*				 * We've been given a pointer				 * to a single buffer.				 */				if ((ccbh->flags & CAM_DATA_PHYS) == 0) {					int s;					int error;

⌨️ 快捷键说明

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