adwcam.c revision 241588
1139749Simp/*-
2218909Sbrucec * CAM SCSI interface for the Advanced Systems Inc.
340024Sgibbs * Second Generation SCSI controllers.
440024Sgibbs *
540024Sgibbs * Product specific probe and attach routines can be found in:
640024Sgibbs *
756979Sgibbs * adw_pci.c	ABP[3]940UW, ABP950UW, ABP3940U2W
840024Sgibbs *
956979Sgibbs * Copyright (c) 1998, 1999, 2000 Justin Gibbs.
1040024Sgibbs * All rights reserved.
1140024Sgibbs *
1240024Sgibbs * Redistribution and use in source and binary forms, with or without
1340024Sgibbs * modification, are permitted provided that the following conditions
1440024Sgibbs * are met:
1540024Sgibbs * 1. Redistributions of source code must retain the above copyright
1640024Sgibbs *    notice, this list of conditions, and the following disclaimer,
1756979Sgibbs *    without modification.
1840024Sgibbs * 2. The name of the author may not be used to endorse or promote products
1940024Sgibbs *    derived from this software without specific prior written permission.
2040024Sgibbs *
2140024Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2240024Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2340024Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2440024Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2540024Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2640024Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2740024Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2840024Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2940024Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3040024Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3140024Sgibbs * SUCH DAMAGE.
3240024Sgibbs */
3340024Sgibbs/*
3440024Sgibbs * Ported from:
3540024Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
3640024Sgibbs *
3740024Sgibbs * Copyright (c) 1995-1998 Advanced System Products, Inc.
3840024Sgibbs * All Rights Reserved.
3940024Sgibbs *
4040024Sgibbs * Redistribution and use in source and binary forms, with or without
4140024Sgibbs * modification, are permitted provided that redistributions of source
4240024Sgibbs * code retain the above copyright notice and this comment without
4340024Sgibbs * modification.
4440024Sgibbs */
4540024Sgibbs
46119418Sobrien#include <sys/cdefs.h>
47119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/advansys/adwcam.c 241588 2012-10-15 15:26:00Z jhb $");
48119418Sobrien
4940024Sgibbs#include <sys/param.h>
50241588Sjhb#include <sys/conf.h>
5140024Sgibbs#include <sys/systm.h>
5240024Sgibbs#include <sys/kernel.h>
5340024Sgibbs#include <sys/malloc.h>
54117126Sscottl#include <sys/lock.h>
55165102Smjacob#include <sys/module.h>
56117126Sscottl#include <sys/mutex.h>
5756979Sgibbs#include <sys/bus.h>
5840024Sgibbs
5940024Sgibbs#include <machine/bus.h>
6056979Sgibbs#include <machine/resource.h>
6140024Sgibbs
6256979Sgibbs#include <sys/rman.h>
6356979Sgibbs
6440024Sgibbs#include <cam/cam.h>
6540024Sgibbs#include <cam/cam_ccb.h>
6640024Sgibbs#include <cam/cam_sim.h>
6740024Sgibbs#include <cam/cam_xpt_sim.h>
6840024Sgibbs#include <cam/cam_debug.h>
6940024Sgibbs
7040024Sgibbs#include <cam/scsi/scsi_message.h>
7140024Sgibbs
7240024Sgibbs#include <dev/advansys/adwvar.h>
7340024Sgibbs
7440024Sgibbs/* Definitions for our use of the SIM private CCB area */
7540024Sgibbs#define ccb_acb_ptr spriv_ptr0
7640024Sgibbs#define ccb_adw_ptr spriv_ptr1
7740024Sgibbs
7857679Sgibbsstatic __inline cam_status	adwccbstatus(union ccb*);
7940024Sgibbsstatic __inline struct acb*	adwgetacb(struct adw_softc *adw);
8040024Sgibbsstatic __inline void		adwfreeacb(struct adw_softc *adw,
8140024Sgibbs					   struct acb *acb);
8240024Sgibbs
8340024Sgibbsstatic void		adwmapmem(void *arg, bus_dma_segment_t *segs,
8440024Sgibbs				  int nseg, int error);
8540024Sgibbsstatic struct sg_map_node*
8640024Sgibbs			adwallocsgmap(struct adw_softc *adw);
8740024Sgibbsstatic int		adwallocacbs(struct adw_softc *adw);
8840024Sgibbs
8940024Sgibbsstatic void		adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs,
9040024Sgibbs				      int nseg, int error);
9140024Sgibbsstatic void		adw_action(struct cam_sim *sim, union ccb *ccb);
92241588Sjhbstatic void		adw_intr_locked(struct adw_softc *adw);
9340024Sgibbsstatic void		adw_poll(struct cam_sim *sim);
9440024Sgibbsstatic void		adw_async(void *callback_arg, u_int32_t code,
9540024Sgibbs				  struct cam_path *path, void *arg);
9640024Sgibbsstatic void		adwprocesserror(struct adw_softc *adw, struct acb *acb);
9740024Sgibbsstatic void		adwtimeout(void *arg);
9840024Sgibbsstatic void		adw_handle_device_reset(struct adw_softc *adw,
9940024Sgibbs						u_int target);
10040024Sgibbsstatic void		adw_handle_bus_reset(struct adw_softc *adw,
10140024Sgibbs					     int initiated);
10240024Sgibbs
10357679Sgibbsstatic __inline cam_status
10457679Sgibbsadwccbstatus(union ccb* ccb)
10557679Sgibbs{
10657679Sgibbs	return (ccb->ccb_h.status & CAM_STATUS_MASK);
10757679Sgibbs}
10857679Sgibbs
10940024Sgibbsstatic __inline struct acb*
11040024Sgibbsadwgetacb(struct adw_softc *adw)
11140024Sgibbs{
11240024Sgibbs	struct	acb* acb;
11340024Sgibbs
114241588Sjhb	if (!dumping)
115241588Sjhb		mtx_assert(&adw->lock, MA_OWNED);
11640024Sgibbs	if ((acb = SLIST_FIRST(&adw->free_acb_list)) != NULL) {
11740024Sgibbs		SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
11840024Sgibbs	} else if (adw->num_acbs < adw->max_acbs) {
11940024Sgibbs		adwallocacbs(adw);
12040024Sgibbs		acb = SLIST_FIRST(&adw->free_acb_list);
12140024Sgibbs		if (acb == NULL)
122241588Sjhb			device_printf(adw->device, "Can't malloc ACB\n");
12340024Sgibbs		else {
12440024Sgibbs			SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
12540024Sgibbs		}
12640024Sgibbs	}
12740024Sgibbs
12840024Sgibbs	return (acb);
12940024Sgibbs}
13040024Sgibbs
13140024Sgibbsstatic __inline void
13240024Sgibbsadwfreeacb(struct adw_softc *adw, struct acb *acb)
13340024Sgibbs{
13440024Sgibbs
135241588Sjhb	if (!dumping)
136241588Sjhb		mtx_assert(&adw->lock, MA_OWNED);
13740024Sgibbs	if ((acb->state & ACB_ACTIVE) != 0)
13840024Sgibbs		LIST_REMOVE(&acb->ccb->ccb_h, sim_links.le);
13940024Sgibbs	if ((acb->state & ACB_RELEASE_SIMQ) != 0)
14040024Sgibbs		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
14140024Sgibbs	else if ((adw->state & ADW_RESOURCE_SHORTAGE) != 0
14240024Sgibbs	      && (acb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
14340024Sgibbs		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
14440024Sgibbs		adw->state &= ~ADW_RESOURCE_SHORTAGE;
14540024Sgibbs	}
14640024Sgibbs	acb->state = ACB_FREE;
14740024Sgibbs	SLIST_INSERT_HEAD(&adw->free_acb_list, acb, links);
14840024Sgibbs}
14940024Sgibbs
15040024Sgibbsstatic void
15140024Sgibbsadwmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
15240024Sgibbs{
15340024Sgibbs	bus_addr_t *busaddrp;
15440024Sgibbs
15540024Sgibbs	busaddrp = (bus_addr_t *)arg;
15640024Sgibbs	*busaddrp = segs->ds_addr;
15740024Sgibbs}
15840024Sgibbs
15940024Sgibbsstatic struct sg_map_node *
16040024Sgibbsadwallocsgmap(struct adw_softc *adw)
16140024Sgibbs{
16240024Sgibbs	struct sg_map_node *sg_map;
16340024Sgibbs
16440024Sgibbs	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
16540024Sgibbs
16640024Sgibbs	if (sg_map == NULL)
16740024Sgibbs		return (NULL);
16840024Sgibbs
16940024Sgibbs	/* Allocate S/G space for the next batch of ACBS */
17040024Sgibbs	if (bus_dmamem_alloc(adw->sg_dmat, (void **)&sg_map->sg_vaddr,
17140024Sgibbs			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
17240024Sgibbs		free(sg_map, M_DEVBUF);
17340024Sgibbs		return (NULL);
17440024Sgibbs	}
17540024Sgibbs
17640024Sgibbs	SLIST_INSERT_HEAD(&adw->sg_maps, sg_map, links);
17740024Sgibbs
17840024Sgibbs	bus_dmamap_load(adw->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
17940024Sgibbs			PAGE_SIZE, adwmapmem, &sg_map->sg_physaddr, /*flags*/0);
18040024Sgibbs
18140024Sgibbs	bzero(sg_map->sg_vaddr, PAGE_SIZE);
18240024Sgibbs	return (sg_map);
18340024Sgibbs}
18440024Sgibbs
18540024Sgibbs/*
18640024Sgibbs * Allocate another chunk of CCB's. Return count of entries added.
18740024Sgibbs */
18840024Sgibbsstatic int
18940024Sgibbsadwallocacbs(struct adw_softc *adw)
19040024Sgibbs{
19140024Sgibbs	struct acb *next_acb;
19240024Sgibbs	struct sg_map_node *sg_map;
19340024Sgibbs	bus_addr_t busaddr;
19440024Sgibbs	struct adw_sg_block *blocks;
19540024Sgibbs	int newcount;
19640024Sgibbs	int i;
19740024Sgibbs
19840024Sgibbs	next_acb = &adw->acbs[adw->num_acbs];
19940024Sgibbs	sg_map = adwallocsgmap(adw);
20040024Sgibbs
20140024Sgibbs	if (sg_map == NULL)
20240024Sgibbs		return (0);
20340024Sgibbs
20440024Sgibbs	blocks = sg_map->sg_vaddr;
20540024Sgibbs	busaddr = sg_map->sg_physaddr;
20640024Sgibbs
20740024Sgibbs	newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks)));
20840024Sgibbs	for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) {
20940024Sgibbs		int error;
21040024Sgibbs
21140024Sgibbs		error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0,
21240024Sgibbs					  &next_acb->dmamap);
21340024Sgibbs		if (error != 0)
21440024Sgibbs			break;
21556979Sgibbs		next_acb->queue.scsi_req_baddr = acbvtob(adw, next_acb);
21656979Sgibbs		next_acb->queue.scsi_req_bo = acbvtobo(adw, next_acb);
21756979Sgibbs		next_acb->queue.sense_baddr =
21856979Sgibbs		    acbvtob(adw, next_acb) + offsetof(struct acb, sense_data);
21940024Sgibbs		next_acb->sg_blocks = blocks;
22040024Sgibbs		next_acb->sg_busaddr = busaddr;
22140024Sgibbs		next_acb->state = ACB_FREE;
222241588Sjhb		callout_init_mtx(&next_acb->timer, &adw->lock, 0);
22340024Sgibbs		SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links);
22440024Sgibbs		blocks += ADW_SG_BLOCKCNT;
22540024Sgibbs		busaddr += ADW_SG_BLOCKCNT * sizeof(*blocks);
22640024Sgibbs		next_acb++;
22740024Sgibbs		adw->num_acbs++;
22840024Sgibbs	}
22940024Sgibbs	return (i);
23040024Sgibbs}
23140024Sgibbs
23240024Sgibbsstatic void
23340024Sgibbsadwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
23440024Sgibbs{
23540024Sgibbs	struct	 acb *acb;
23640024Sgibbs	union	 ccb *ccb;
23740024Sgibbs	struct	 adw_softc *adw;
23840024Sgibbs
23940024Sgibbs	acb = (struct acb *)arg;
24040024Sgibbs	ccb = acb->ccb;
24140024Sgibbs	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
24240024Sgibbs
243241588Sjhb	if (!dumping)
244241588Sjhb		mtx_assert(&adw->lock, MA_OWNED);
24540024Sgibbs	if (error != 0) {
24640024Sgibbs		if (error != EFBIG)
247241588Sjhb			device_printf(adw->device, "Unexepected error 0x%x "
248241588Sjhb			    "returned from bus_dmamap_load\n", error);
24940024Sgibbs		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
25040024Sgibbs			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
25140024Sgibbs			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
25240024Sgibbs		}
25340024Sgibbs		adwfreeacb(adw, acb);
25440024Sgibbs		xpt_done(ccb);
25540024Sgibbs		return;
25640024Sgibbs	}
25740024Sgibbs
25840024Sgibbs	if (nseg != 0) {
259115343Sscottl		bus_dmasync_op_t op;
26040024Sgibbs
26140024Sgibbs		acb->queue.data_addr = dm_segs[0].ds_addr;
26240024Sgibbs		acb->queue.data_cnt = ccb->csio.dxfer_len;
26340024Sgibbs		if (nseg > 1) {
26440024Sgibbs			struct adw_sg_block *sg_block;
26540024Sgibbs			struct adw_sg_elm *sg;
26640024Sgibbs			bus_addr_t sg_busaddr;
26740024Sgibbs			u_int sg_index;
26840024Sgibbs			bus_dma_segment_t *end_seg;
26940024Sgibbs
27040024Sgibbs			end_seg = dm_segs + nseg;
27140024Sgibbs
27240024Sgibbs			sg_busaddr = acb->sg_busaddr;
27340024Sgibbs			sg_index = 0;
27440024Sgibbs			/* Copy the segments into our SG list */
27540024Sgibbs			for (sg_block = acb->sg_blocks;; sg_block++) {
27656979Sgibbs				u_int i;
27740024Sgibbs
27840024Sgibbs				sg = sg_block->sg_list;
27956979Sgibbs				for (i = 0; i < ADW_NO_OF_SG_PER_BLOCK; i++) {
28056979Sgibbs					if (dm_segs >= end_seg)
28156979Sgibbs						break;
28256979Sgibbs
28340024Sgibbs					sg->sg_addr = dm_segs->ds_addr;
28440024Sgibbs					sg->sg_count = dm_segs->ds_len;
28540024Sgibbs					sg++;
28640024Sgibbs					dm_segs++;
28740024Sgibbs				}
28856979Sgibbs				sg_block->sg_cnt = i;
28956979Sgibbs				sg_index += i;
29040024Sgibbs				if (dm_segs == end_seg) {
29140024Sgibbs					sg_block->sg_busaddr_next = 0;
29240024Sgibbs					break;
29340024Sgibbs				} else {
29440024Sgibbs					sg_busaddr +=
29540024Sgibbs					    sizeof(struct adw_sg_block);
29640024Sgibbs					sg_block->sg_busaddr_next = sg_busaddr;
29740024Sgibbs				}
29840024Sgibbs			}
29940024Sgibbs			acb->queue.sg_real_addr = acb->sg_busaddr;
30040024Sgibbs		} else {
30140024Sgibbs			acb->queue.sg_real_addr = 0;
30240024Sgibbs		}
30340024Sgibbs
30440024Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
30540024Sgibbs			op = BUS_DMASYNC_PREREAD;
30640024Sgibbs		else
30740024Sgibbs			op = BUS_DMASYNC_PREWRITE;
30840024Sgibbs
30940024Sgibbs		bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
31040024Sgibbs
31140024Sgibbs	} else {
31240024Sgibbs		acb->queue.data_addr = 0;
31340024Sgibbs		acb->queue.data_cnt = 0;
31440024Sgibbs		acb->queue.sg_real_addr = 0;
31540024Sgibbs	}
31640024Sgibbs
31740024Sgibbs	/*
31840024Sgibbs	 * Last time we need to check if this CCB needs to
31940024Sgibbs	 * be aborted.
32040024Sgibbs	 */
32140024Sgibbs	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
32240024Sgibbs		if (nseg != 0)
32340024Sgibbs			bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
32440024Sgibbs		adwfreeacb(adw, acb);
32540024Sgibbs		xpt_done(ccb);
32640024Sgibbs		return;
32740024Sgibbs	}
32857679Sgibbs
32940024Sgibbs	acb->state |= ACB_ACTIVE;
33040024Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
33140024Sgibbs	LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le);
332241588Sjhb	callout_reset(&acb->timer, (ccb->ccb_h.timeout * hz) / 1000,
333241588Sjhb	    adwtimeout, acb);
33440024Sgibbs
33556979Sgibbs	adw_send_acb(adw, acb, acbvtob(adw, acb));
33640024Sgibbs}
33740024Sgibbs
33840024Sgibbsstatic void
33940024Sgibbsadw_action(struct cam_sim *sim, union ccb *ccb)
34040024Sgibbs{
34140024Sgibbs	struct	adw_softc *adw;
34240024Sgibbs
34340024Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adw_action\n"));
34440024Sgibbs
34540024Sgibbs	adw = (struct adw_softc *)cam_sim_softc(sim);
346241588Sjhb	if (!dumping)
347241588Sjhb		mtx_assert(&adw->lock, MA_OWNED);
34840024Sgibbs
34940024Sgibbs	switch (ccb->ccb_h.func_code) {
35040024Sgibbs	/* Common cases first */
35140024Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
35240024Sgibbs	{
35340024Sgibbs		struct	ccb_scsiio *csio;
35440024Sgibbs		struct	ccb_hdr *ccbh;
35540024Sgibbs		struct	acb *acb;
35640024Sgibbs
35740024Sgibbs		csio = &ccb->csio;
35840024Sgibbs		ccbh = &ccb->ccb_h;
35956979Sgibbs
36040024Sgibbs		/* Max supported CDB length is 12 bytes */
36140024Sgibbs		if (csio->cdb_len > 12) {
36240024Sgibbs			ccb->ccb_h.status = CAM_REQ_INVALID;
36340024Sgibbs			xpt_done(ccb);
36440024Sgibbs			return;
36540024Sgibbs		}
36640024Sgibbs
36740024Sgibbs		if ((acb = adwgetacb(adw)) == NULL) {
36840024Sgibbs			adw->state |= ADW_RESOURCE_SHORTAGE;
36940024Sgibbs			xpt_freeze_simq(sim, /*count*/1);
37040024Sgibbs			ccb->ccb_h.status = CAM_REQUEUE_REQ;
37140024Sgibbs			xpt_done(ccb);
37240024Sgibbs			return;
37340024Sgibbs		}
37440024Sgibbs
37556979Sgibbs		/* Link acb and ccb so we can find one from the other */
37640024Sgibbs		acb->ccb = ccb;
37740024Sgibbs		ccb->ccb_h.ccb_acb_ptr = acb;
37840024Sgibbs		ccb->ccb_h.ccb_adw_ptr = adw;
37940024Sgibbs
38040024Sgibbs		acb->queue.cntl = 0;
38156979Sgibbs		acb->queue.target_cmd = 0;
38240024Sgibbs		acb->queue.target_id = ccb->ccb_h.target_id;
38340024Sgibbs		acb->queue.target_lun = ccb->ccb_h.target_lun;
38440024Sgibbs
38556979Sgibbs		acb->queue.mflag = 0;
38640024Sgibbs		acb->queue.sense_len =
38740024Sgibbs			MIN(csio->sense_len, sizeof(acb->sense_data));
38840024Sgibbs		acb->queue.cdb_len = csio->cdb_len;
38956979Sgibbs		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
39056979Sgibbs			switch (csio->tag_action) {
39156979Sgibbs			case MSG_SIMPLE_Q_TAG:
39257679Sgibbs				acb->queue.scsi_cntl = ADW_QSC_SIMPLE_Q_TAG;
39356979Sgibbs				break;
39456979Sgibbs			case MSG_HEAD_OF_Q_TAG:
39556979Sgibbs				acb->queue.scsi_cntl = ADW_QSC_HEAD_OF_Q_TAG;
39656979Sgibbs				break;
39756979Sgibbs			case MSG_ORDERED_Q_TAG:
39856979Sgibbs				acb->queue.scsi_cntl = ADW_QSC_ORDERED_Q_TAG;
39956979Sgibbs				break;
40057679Sgibbs			default:
40157679Sgibbs				acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
40257679Sgibbs				break;
40356979Sgibbs			}
40456979Sgibbs		} else
40556979Sgibbs			acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
40640024Sgibbs
40756979Sgibbs		if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
40856979Sgibbs			acb->queue.scsi_cntl |= ADW_QSC_NO_DISC;
40940024Sgibbs
41040024Sgibbs		acb->queue.done_status = 0;
41140024Sgibbs		acb->queue.scsi_status = 0;
41240024Sgibbs		acb->queue.host_status = 0;
41356979Sgibbs		acb->queue.sg_wk_ix = 0;
41440024Sgibbs		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
41540024Sgibbs			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
41640024Sgibbs				bcopy(csio->cdb_io.cdb_ptr,
41740024Sgibbs				      acb->queue.cdb, csio->cdb_len);
41840024Sgibbs			} else {
41940024Sgibbs				/* I guess I could map it in... */
42040024Sgibbs				ccb->ccb_h.status = CAM_REQ_INVALID;
42140024Sgibbs				adwfreeacb(adw, acb);
42240024Sgibbs				xpt_done(ccb);
42340024Sgibbs				return;
42440024Sgibbs			}
42540024Sgibbs		} else {
42640024Sgibbs			bcopy(csio->cdb_io.cdb_bytes,
42740024Sgibbs			      acb->queue.cdb, csio->cdb_len);
42840024Sgibbs		}
42940024Sgibbs
43040024Sgibbs		/*
43140024Sgibbs		 * If we have any data to send with this command,
43240024Sgibbs		 * map it into bus space.
43340024Sgibbs		 */
43440024Sgibbs		if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
43540024Sgibbs			if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
43640024Sgibbs				/*
43740024Sgibbs				 * We've been given a pointer
43840024Sgibbs				 * to a single buffer.
43940024Sgibbs				 */
44040024Sgibbs				if ((ccbh->flags & CAM_DATA_PHYS) == 0) {
44140024Sgibbs					int error;
44240024Sgibbs
44340024Sgibbs					error =
44440024Sgibbs					    bus_dmamap_load(adw->buffer_dmat,
44540024Sgibbs							    acb->dmamap,
44640024Sgibbs							    csio->data_ptr,
44740024Sgibbs							    csio->dxfer_len,
44840024Sgibbs							    adwexecuteacb,
44940024Sgibbs							    acb, /*flags*/0);
45040024Sgibbs					if (error == EINPROGRESS) {
45140024Sgibbs						/*
45240024Sgibbs						 * So as to maintain ordering,
45340024Sgibbs						 * freeze the controller queue
45440024Sgibbs						 * until our mapping is
45540024Sgibbs						 * returned.
45640024Sgibbs						 */
45740024Sgibbs						xpt_freeze_simq(sim, 1);
45840024Sgibbs						acb->state |= CAM_RELEASE_SIMQ;
45940024Sgibbs					}
46040024Sgibbs				} else {
46140024Sgibbs					struct bus_dma_segment seg;
46240024Sgibbs
46340024Sgibbs					/* Pointer to physical buffer */
46440024Sgibbs					seg.ds_addr =
46540024Sgibbs					    (bus_addr_t)csio->data_ptr;
46640024Sgibbs					seg.ds_len = csio->dxfer_len;
46740024Sgibbs					adwexecuteacb(acb, &seg, 1, 0);
46840024Sgibbs				}
46940024Sgibbs			} else {
47040024Sgibbs				struct bus_dma_segment *segs;
47140024Sgibbs
47240024Sgibbs				if ((ccbh->flags & CAM_DATA_PHYS) != 0)
47340024Sgibbs					panic("adw_action - Physical "
47440024Sgibbs					      "segment pointers "
47540024Sgibbs					      "unsupported");
47640024Sgibbs
47740024Sgibbs				if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
47840024Sgibbs					panic("adw_action - Virtual "
47940024Sgibbs					      "segment addresses "
48040024Sgibbs					      "unsupported");
48140024Sgibbs
48240024Sgibbs				/* Just use the segments provided */
48340024Sgibbs				segs = (struct bus_dma_segment *)csio->data_ptr;
48440024Sgibbs				adwexecuteacb(acb, segs, csio->sglist_cnt,
48540024Sgibbs					      (csio->sglist_cnt < ADW_SGSIZE)
48640024Sgibbs					      ? 0 : EFBIG);
48740024Sgibbs			}
48840024Sgibbs		} else {
48940024Sgibbs			adwexecuteacb(acb, NULL, 0, 0);
49040024Sgibbs		}
49140024Sgibbs		break;
49240024Sgibbs	}
49340024Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
49440024Sgibbs	{
49540024Sgibbs		adw_idle_cmd_status_t status;
49640024Sgibbs
49757679Sgibbs		status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
49857679Sgibbs					   ccb->ccb_h.target_id);
49940024Sgibbs		if (status == ADW_IDLE_CMD_SUCCESS) {
50040024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
50140024Sgibbs			if (bootverbose) {
50240024Sgibbs				xpt_print_path(ccb->ccb_h.path);
50340024Sgibbs				printf("BDR Delivered\n");
50440024Sgibbs			}
50540024Sgibbs		} else
50640024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
50740024Sgibbs		xpt_done(ccb);
50840024Sgibbs		break;
50940024Sgibbs	}
51040024Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
51140024Sgibbs		/* XXX Implement */
51240024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
51340024Sgibbs		xpt_done(ccb);
51440024Sgibbs		break;
51540024Sgibbs	case XPT_SET_TRAN_SETTINGS:
51640024Sgibbs	{
517163816Smjacob		struct ccb_trans_settings_scsi *scsi;
518163816Smjacob		struct ccb_trans_settings_spi *spi;
51940024Sgibbs		struct	  ccb_trans_settings *cts;
52040024Sgibbs		u_int	  target_mask;
52140024Sgibbs
52240024Sgibbs		cts = &ccb->cts;
52340024Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
52440024Sgibbs
525163816Smjacob		scsi = &cts->proto_specific.scsi;
526163816Smjacob		spi = &cts->xport_specific.spi;
527163816Smjacob		if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
528163816Smjacob			u_int sdtrdone;
529163816Smjacob
530163816Smjacob			sdtrdone = adw_lram_read_16(adw, ADW_MC_SDTR_DONE);
531163816Smjacob			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
532163816Smjacob				u_int discenb;
533163816Smjacob
534163816Smjacob				discenb =
535163816Smjacob				    adw_lram_read_16(adw, ADW_MC_DISC_ENABLE);
536163816Smjacob
537163816Smjacob				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
538163816Smjacob					discenb |= target_mask;
539163816Smjacob				else
540163816Smjacob					discenb &= ~target_mask;
541163816Smjacob
542163816Smjacob				adw_lram_write_16(adw, ADW_MC_DISC_ENABLE,
543163816Smjacob						  discenb);
544163816Smjacob			}
545163816Smjacob
546163816Smjacob			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
547163816Smjacob
548163816Smjacob				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
549163816Smjacob					adw->tagenb |= target_mask;
550163816Smjacob				else
551163816Smjacob					adw->tagenb &= ~target_mask;
552163816Smjacob			}
553163816Smjacob
554163816Smjacob			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
555163816Smjacob				u_int wdtrenb_orig;
556163816Smjacob				u_int wdtrenb;
557163816Smjacob				u_int wdtrdone;
558163816Smjacob
559163816Smjacob				wdtrenb_orig =
560163816Smjacob				    adw_lram_read_16(adw, ADW_MC_WDTR_ABLE);
561163816Smjacob				wdtrenb = wdtrenb_orig;
562163816Smjacob				wdtrdone = adw_lram_read_16(adw,
563163816Smjacob							    ADW_MC_WDTR_DONE);
564163816Smjacob				switch (spi->bus_width) {
565163816Smjacob				case MSG_EXT_WDTR_BUS_32_BIT:
566163816Smjacob				case MSG_EXT_WDTR_BUS_16_BIT:
567163816Smjacob					wdtrenb |= target_mask;
568163816Smjacob					break;
569163816Smjacob				case MSG_EXT_WDTR_BUS_8_BIT:
570163816Smjacob				default:
571163816Smjacob					wdtrenb &= ~target_mask;
572163816Smjacob					break;
573163816Smjacob				}
574163816Smjacob				if (wdtrenb != wdtrenb_orig) {
575163816Smjacob					adw_lram_write_16(adw,
576163816Smjacob							  ADW_MC_WDTR_ABLE,
577163816Smjacob							  wdtrenb);
578163816Smjacob					wdtrdone &= ~target_mask;
579163816Smjacob					adw_lram_write_16(adw,
580163816Smjacob							  ADW_MC_WDTR_DONE,
581163816Smjacob							  wdtrdone);
582163816Smjacob					/* Wide negotiation forces async */
583163816Smjacob					sdtrdone &= ~target_mask;
584163816Smjacob					adw_lram_write_16(adw,
585163816Smjacob							  ADW_MC_SDTR_DONE,
586163816Smjacob							  sdtrdone);
587163816Smjacob				}
588163816Smjacob			}
589163816Smjacob
590163816Smjacob			if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0)
591163816Smjacob			 || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) {
592163816Smjacob				u_int sdtr_orig;
593163816Smjacob				u_int sdtr;
594163816Smjacob				u_int sdtrable_orig;
595163816Smjacob				u_int sdtrable;
596163816Smjacob
597163816Smjacob				sdtr = adw_get_chip_sdtr(adw,
598163816Smjacob							 ccb->ccb_h.target_id);
599163816Smjacob				sdtr_orig = sdtr;
600163816Smjacob				sdtrable = adw_lram_read_16(adw,
601163816Smjacob							    ADW_MC_SDTR_ABLE);
602163816Smjacob				sdtrable_orig = sdtrable;
603163816Smjacob
604163816Smjacob				if ((spi->valid
605163816Smjacob				   & CTS_SPI_VALID_SYNC_RATE) != 0) {
606163816Smjacob
607163816Smjacob					sdtr =
608163816Smjacob					    adw_find_sdtr(adw,
609163816Smjacob							  spi->sync_period);
610163816Smjacob				}
611163816Smjacob
612163816Smjacob				if ((spi->valid
613163816Smjacob				   & CTS_SPI_VALID_SYNC_OFFSET) != 0) {
614163816Smjacob					if (spi->sync_offset == 0)
615163816Smjacob						sdtr = ADW_MC_SDTR_ASYNC;
616163816Smjacob				}
617163816Smjacob
618163816Smjacob				if (sdtr == ADW_MC_SDTR_ASYNC)
619163816Smjacob					sdtrable &= ~target_mask;
620163816Smjacob				else
621163816Smjacob					sdtrable |= target_mask;
622163816Smjacob				if (sdtr != sdtr_orig
623163816Smjacob				 || sdtrable != sdtrable_orig) {
624163816Smjacob					adw_set_chip_sdtr(adw,
625163816Smjacob							  ccb->ccb_h.target_id,
626163816Smjacob							  sdtr);
627163816Smjacob					sdtrdone &= ~target_mask;
628163816Smjacob					adw_lram_write_16(adw, ADW_MC_SDTR_ABLE,
629163816Smjacob							  sdtrable);
630163816Smjacob					adw_lram_write_16(adw, ADW_MC_SDTR_DONE,
631163816Smjacob							  sdtrdone);
632163816Smjacob
633163816Smjacob				}
634163816Smjacob			}
635163816Smjacob		}
63640024Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
63740024Sgibbs		xpt_done(ccb);
63840024Sgibbs		break;
63940024Sgibbs	}
64040024Sgibbs	case XPT_GET_TRAN_SETTINGS:
64140024Sgibbs	/* Get default/user set transfer settings for the target */
64240024Sgibbs	{
643163816Smjacob		struct ccb_trans_settings_scsi *scsi;
644163816Smjacob		struct ccb_trans_settings_spi *spi;
64540024Sgibbs		struct	ccb_trans_settings *cts;
64640024Sgibbs		u_int	target_mask;
64740024Sgibbs
64840024Sgibbs		cts = &ccb->cts;
64940024Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
650163816Smjacob		cts->protocol = PROTO_SCSI;
651163816Smjacob		cts->protocol_version = SCSI_REV_2;
652163816Smjacob		cts->transport = XPORT_SPI;
653163816Smjacob		cts->transport_version = 2;
654163816Smjacob
655163816Smjacob		scsi = &cts->proto_specific.scsi;
656163816Smjacob		spi = &cts->xport_specific.spi;
657163816Smjacob		if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
65856979Sgibbs			u_int mc_sdtr;
65956979Sgibbs
660163816Smjacob			spi->flags = 0;
661163816Smjacob			if ((adw->user_discenb & target_mask) != 0)
662163816Smjacob				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
663163816Smjacob
664163816Smjacob			if ((adw->user_tagenb & target_mask) != 0)
665163816Smjacob				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
666163816Smjacob
667163816Smjacob			if ((adw->user_wdtr & target_mask) != 0)
668163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
669163816Smjacob			else
670163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
671163816Smjacob
672163816Smjacob			mc_sdtr = adw_get_user_sdtr(adw, ccb->ccb_h.target_id);
673163816Smjacob			spi->sync_period = adw_find_period(adw, mc_sdtr);
674163816Smjacob			if (spi->sync_period != 0)
675163816Smjacob				spi->sync_offset = 15; /* XXX ??? */
676163816Smjacob			else
677163816Smjacob				spi->sync_offset = 0;
678163816Smjacob
679163816Smjacob
680163816Smjacob		} else {
681163816Smjacob			u_int targ_tinfo;
682163816Smjacob
683163816Smjacob			spi->flags = 0;
684163816Smjacob			if ((adw_lram_read_16(adw, ADW_MC_DISC_ENABLE)
685163816Smjacob			  & target_mask) != 0)
686163816Smjacob				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
687163816Smjacob
688163816Smjacob			if ((adw->tagenb & target_mask) != 0)
689163816Smjacob				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
690163816Smjacob
691163816Smjacob			targ_tinfo =
692163816Smjacob			    adw_lram_read_16(adw,
693163816Smjacob					     ADW_MC_DEVICE_HSHK_CFG_TABLE
694163816Smjacob					     + (2 * ccb->ccb_h.target_id));
695163816Smjacob
696163816Smjacob			if ((targ_tinfo & ADW_HSHK_CFG_WIDE_XFR) != 0)
697163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
698163816Smjacob			else
699163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
700163816Smjacob
701163816Smjacob			spi->sync_period =
702163816Smjacob			    adw_hshk_cfg_period_factor(targ_tinfo);
703163816Smjacob
704163816Smjacob			spi->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET;
705163816Smjacob			if (spi->sync_period == 0)
706163816Smjacob				spi->sync_offset = 0;
707163816Smjacob
708163816Smjacob			if (spi->sync_offset == 0)
709163816Smjacob				spi->sync_period = 0;
710163816Smjacob		}
711163816Smjacob
712163816Smjacob		spi->valid = CTS_SPI_VALID_SYNC_RATE
713163816Smjacob			   | CTS_SPI_VALID_SYNC_OFFSET
714163816Smjacob			   | CTS_SPI_VALID_BUS_WIDTH
715163816Smjacob			   | CTS_SPI_VALID_DISC;
716163816Smjacob		scsi->valid = CTS_SCSI_VALID_TQ;
71740024Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
71840024Sgibbs		xpt_done(ccb);
71940024Sgibbs		break;
72040024Sgibbs	}
72140024Sgibbs	case XPT_CALC_GEOMETRY:
72240024Sgibbs	{
72340024Sgibbs		/*
72440024Sgibbs		 * XXX Use Adaptec translation until I find out how to
72540024Sgibbs		 *     get this information from the card.
72640024Sgibbs		 */
727116351Snjl		cam_calc_geometry(&ccb->ccg, /*extended*/1);
72840024Sgibbs		xpt_done(ccb);
72940024Sgibbs		break;
73040024Sgibbs	}
73140024Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
73240024Sgibbs	{
73357679Sgibbs		int failure;
73440024Sgibbs
73557679Sgibbs		failure = adw_reset_bus(adw);
73657679Sgibbs		if (failure != 0) {
73740024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
73857679Sgibbs		} else {
73957679Sgibbs			if (bootverbose) {
74057679Sgibbs				xpt_print_path(adw->path);
74157679Sgibbs				printf("Bus Reset Delivered\n");
74257679Sgibbs			}
74357679Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
74456979Sgibbs		}
74540024Sgibbs		xpt_done(ccb);
74640024Sgibbs		break;
74740024Sgibbs	}
74840024Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
74940024Sgibbs		/* XXX Implement */
75040024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
75140024Sgibbs		xpt_done(ccb);
75240024Sgibbs		break;
75340024Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
75440024Sgibbs	{
75540024Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
75640024Sgibbs
75740024Sgibbs		cpi->version_num = 1;
75840024Sgibbs		cpi->hba_inquiry = PI_WIDE_16|PI_SDTR_ABLE|PI_TAG_ABLE;
75940024Sgibbs		cpi->target_sprt = 0;
76040024Sgibbs		cpi->hba_misc = 0;
76140024Sgibbs		cpi->hba_eng_cnt = 0;
76240024Sgibbs		cpi->max_target = ADW_MAX_TID;
76340024Sgibbs		cpi->max_lun = ADW_MAX_LUN;
76440024Sgibbs		cpi->initiator_id = adw->initiator_id;
76540024Sgibbs		cpi->bus_id = cam_sim_bus(sim);
76646581Sken		cpi->base_transfer_speed = 3300;
76740024Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
76840024Sgibbs		strncpy(cpi->hba_vid, "AdvanSys", HBA_IDLEN);
76940024Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
77040024Sgibbs		cpi->unit_number = cam_sim_unit(sim);
771163816Smjacob                cpi->transport = XPORT_SPI;
772163816Smjacob                cpi->transport_version = 2;
773163816Smjacob                cpi->protocol = PROTO_SCSI;
774163816Smjacob                cpi->protocol_version = SCSI_REV_2;
77540024Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
77640024Sgibbs		xpt_done(ccb);
77740024Sgibbs		break;
77840024Sgibbs	}
77940024Sgibbs	default:
78040024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
78140024Sgibbs		xpt_done(ccb);
78240024Sgibbs		break;
78340024Sgibbs	}
78440024Sgibbs}
78540024Sgibbs
78640024Sgibbsstatic void
78740024Sgibbsadw_poll(struct cam_sim *sim)
78840024Sgibbs{
789241588Sjhb	adw_intr_locked(cam_sim_softc(sim));
79040024Sgibbs}
79140024Sgibbs
79240024Sgibbsstatic void
79340024Sgibbsadw_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
79440024Sgibbs{
79540024Sgibbs}
79640024Sgibbs
79740024Sgibbsstruct adw_softc *
79856979Sgibbsadw_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id)
79940024Sgibbs{
80040024Sgibbs	struct	 adw_softc *adw;
801241588Sjhb
802241588Sjhb	adw = device_get_softc(dev);
80340024Sgibbs	LIST_INIT(&adw->pending_ccbs);
80440024Sgibbs	SLIST_INIT(&adw->sg_maps);
805241588Sjhb	mtx_init(&adw->lock, "adw", NULL, MTX_DEF);
80656979Sgibbs	adw->device = dev;
80756979Sgibbs	adw->regs_res_type = regs_type;
80856979Sgibbs	adw->regs_res_id = regs_id;
80956979Sgibbs	adw->regs = regs;
81040024Sgibbs	return(adw);
81140024Sgibbs}
81240024Sgibbs
81340024Sgibbsvoid
81440024Sgibbsadw_free(struct adw_softc *adw)
81540024Sgibbs{
81640024Sgibbs	switch (adw->init_level) {
81756979Sgibbs	case 9:
81840024Sgibbs	{
81940024Sgibbs		struct sg_map_node *sg_map;
82040024Sgibbs
82140024Sgibbs		while ((sg_map = SLIST_FIRST(&adw->sg_maps)) != NULL) {
82240024Sgibbs			SLIST_REMOVE_HEAD(&adw->sg_maps, links);
82340024Sgibbs			bus_dmamap_unload(adw->sg_dmat,
82440024Sgibbs					  sg_map->sg_dmamap);
82540024Sgibbs			bus_dmamem_free(adw->sg_dmat, sg_map->sg_vaddr,
82640024Sgibbs					sg_map->sg_dmamap);
82740024Sgibbs			free(sg_map, M_DEVBUF);
82840024Sgibbs		}
82940024Sgibbs		bus_dma_tag_destroy(adw->sg_dmat);
83040024Sgibbs	}
83156979Sgibbs	case 8:
83240024Sgibbs		bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap);
83356979Sgibbs	case 7:
83440024Sgibbs		bus_dmamem_free(adw->acb_dmat, adw->acbs,
83540024Sgibbs				adw->acb_dmamap);
83640024Sgibbs		bus_dmamap_destroy(adw->acb_dmat, adw->acb_dmamap);
83756979Sgibbs	case 6:
83856979Sgibbs		bus_dma_tag_destroy(adw->acb_dmat);
83956979Sgibbs	case 5:
84056979Sgibbs		bus_dmamap_unload(adw->carrier_dmat, adw->carrier_dmamap);
84156979Sgibbs	case 4:
84256979Sgibbs		bus_dmamem_free(adw->carrier_dmat, adw->carriers,
84356979Sgibbs				adw->carrier_dmamap);
84456979Sgibbs		bus_dmamap_destroy(adw->carrier_dmat, adw->carrier_dmamap);
84540024Sgibbs	case 3:
84656979Sgibbs		bus_dma_tag_destroy(adw->carrier_dmat);
84740024Sgibbs	case 2:
84840024Sgibbs		bus_dma_tag_destroy(adw->buffer_dmat);
84940024Sgibbs	case 1:
85040024Sgibbs		bus_dma_tag_destroy(adw->parent_dmat);
85140024Sgibbs	case 0:
85240024Sgibbs		break;
85340024Sgibbs	}
854138502Srsm
855138502Srsm	if (adw->regs != NULL)
856138502Srsm		bus_release_resource(adw->device,
857138502Srsm				     adw->regs_res_type,
858138502Srsm				     adw->regs_res_id,
859138502Srsm				     adw->regs);
860138502Srsm
861138502Srsm	if (adw->irq != NULL)
862138502Srsm		bus_release_resource(adw->device,
863138502Srsm				     adw->irq_res_type,
864138502Srsm				     0, adw->irq);
865138502Srsm
866138502Srsm	if (adw->sim != NULL) {
867138502Srsm		if (adw->path != NULL) {
868138502Srsm			xpt_async(AC_LOST_DEVICE, adw->path, NULL);
869138502Srsm			xpt_free_path(adw->path);
870138502Srsm		}
871138502Srsm		xpt_bus_deregister(cam_sim_path(adw->sim));
872138502Srsm		cam_sim_free(adw->sim, /*free_devq*/TRUE);
873138502Srsm	}
874241588Sjhb	mtx_destroy(&adw->lock);
87540024Sgibbs}
87640024Sgibbs
87740024Sgibbsint
87840024Sgibbsadw_init(struct adw_softc *adw)
87940024Sgibbs{
88040024Sgibbs	struct	  adw_eeprom eep_config;
88156979Sgibbs	u_int	  tid;
88256979Sgibbs	u_int	  i;
88340024Sgibbs	u_int16_t checksum;
88440024Sgibbs	u_int16_t scsicfg1;
88540024Sgibbs
88640024Sgibbs	checksum = adw_eeprom_read(adw, &eep_config);
88740024Sgibbs	bcopy(eep_config.serial_number, adw->serial_number,
88840024Sgibbs	      sizeof(adw->serial_number));
88940024Sgibbs	if (checksum != eep_config.checksum) {
89040024Sgibbs		u_int16_t serial_number[3];
89140024Sgibbs
89256979Sgibbs		adw->flags |= ADW_EEPROM_FAILED;
893241588Sjhb		device_printf(adw->device,
894241588Sjhb		    "EEPROM checksum failed.  Restoring Defaults\n");
89540024Sgibbs
89640024Sgibbs	        /*
89740024Sgibbs		 * Restore the default EEPROM settings.
89840024Sgibbs		 * Assume the 6 byte board serial number that was read
89940024Sgibbs		 * from EEPROM is correct even if the EEPROM checksum
90040024Sgibbs		 * failed.
90140024Sgibbs		 */
90256979Sgibbs		bcopy(adw->default_eeprom, &eep_config, sizeof(eep_config));
90340024Sgibbs		bcopy(adw->serial_number, eep_config.serial_number,
90440024Sgibbs		      sizeof(serial_number));
90540024Sgibbs		adw_eeprom_write(adw, &eep_config);
90640024Sgibbs	}
90740024Sgibbs
90840024Sgibbs	/* Pull eeprom information into our softc. */
90940024Sgibbs	adw->bios_ctrl = eep_config.bios_ctrl;
91040024Sgibbs	adw->user_wdtr = eep_config.wdtr_able;
91156979Sgibbs	for (tid = 0; tid < ADW_MAX_TID; tid++) {
91256979Sgibbs		u_int	  mc_sdtr;
91356979Sgibbs		u_int16_t tid_mask;
91456979Sgibbs
91556979Sgibbs		tid_mask = 0x1 << tid;
91656979Sgibbs		if ((adw->features & ADW_ULTRA) != 0) {
91756979Sgibbs			/*
91856979Sgibbs			 * Ultra chips store sdtr and ultraenb
91956979Sgibbs			 * bits in their seeprom, so we must
92056979Sgibbs			 * construct valid mc_sdtr entries for
92156979Sgibbs			 * indirectly.
92256979Sgibbs			 */
92356979Sgibbs			if (eep_config.sync1.sync_enable & tid_mask) {
92456979Sgibbs				if (eep_config.sync2.ultra_enable & tid_mask)
92556979Sgibbs					mc_sdtr = ADW_MC_SDTR_20;
92656979Sgibbs				else
92756979Sgibbs					mc_sdtr = ADW_MC_SDTR_10;
92856979Sgibbs			} else
92956979Sgibbs				mc_sdtr = ADW_MC_SDTR_ASYNC;
93056979Sgibbs		} else {
93156979Sgibbs			switch (ADW_TARGET_GROUP(tid)) {
93256979Sgibbs			case 3:
93356979Sgibbs				mc_sdtr = eep_config.sync4.sdtr4;
93456979Sgibbs				break;
93556979Sgibbs			case 2:
93656979Sgibbs				mc_sdtr = eep_config.sync3.sdtr3;
93756979Sgibbs				break;
93856979Sgibbs			case 1:
93956979Sgibbs				mc_sdtr = eep_config.sync2.sdtr2;
94056979Sgibbs				break;
94156979Sgibbs			default: /* Shut up compiler */
94256979Sgibbs			case 0:
94356979Sgibbs				mc_sdtr = eep_config.sync1.sdtr1;
94456979Sgibbs				break;
94556979Sgibbs			}
94656979Sgibbs			mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid);
94756979Sgibbs			mc_sdtr &= 0xFF;
94856979Sgibbs		}
94956979Sgibbs		adw_set_user_sdtr(adw, tid, mc_sdtr);
95056979Sgibbs	}
95140024Sgibbs	adw->user_tagenb = eep_config.tagqng_able;
95240024Sgibbs	adw->user_discenb = eep_config.disc_enable;
95340024Sgibbs	adw->max_acbs = eep_config.max_host_qng;
95440024Sgibbs	adw->initiator_id = (eep_config.adapter_scsi_id & ADW_MAX_TID);
95540024Sgibbs
95640024Sgibbs	/*
95740024Sgibbs	 * Sanity check the number of host openings.
95840024Sgibbs	 */
95940024Sgibbs	if (adw->max_acbs > ADW_DEF_MAX_HOST_QNG)
96040024Sgibbs		adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
96140024Sgibbs	else if (adw->max_acbs < ADW_DEF_MIN_HOST_QNG) {
96240024Sgibbs        	/* If the value is zero, assume it is uninitialized. */
96340024Sgibbs		if (adw->max_acbs == 0)
96440024Sgibbs			adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
96540024Sgibbs		else
96640024Sgibbs			adw->max_acbs = ADW_DEF_MIN_HOST_QNG;
96740024Sgibbs	}
96840024Sgibbs
96940024Sgibbs	scsicfg1 = 0;
97056979Sgibbs	if ((adw->features & ADW_ULTRA2) != 0) {
97156979Sgibbs		switch (eep_config.termination_lvd) {
97256979Sgibbs		default:
973241588Sjhb			device_printf(adw->device,
974241588Sjhb			    "Invalid EEPROM LVD Termination Settings.\n");
975241588Sjhb			device_printf(adw->device,
976241588Sjhb			    "Reverting to Automatic LVD Termination\n");
97756979Sgibbs			/* FALLTHROUGH */
97856979Sgibbs		case ADW_EEPROM_TERM_AUTO:
97956979Sgibbs			break;
98056979Sgibbs		case ADW_EEPROM_TERM_BOTH_ON:
98156979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_LO;
98256979Sgibbs			/* FALLTHROUGH */
98356979Sgibbs		case ADW_EEPROM_TERM_HIGH_ON:
98456979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_HI;
98556979Sgibbs			/* FALLTHROUGH */
98656979Sgibbs		case ADW_EEPROM_TERM_OFF:
98756979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_DIS_TERM_DRV;
98856979Sgibbs			break;
98956979Sgibbs		}
99056979Sgibbs	}
99156979Sgibbs
99256979Sgibbs	switch (eep_config.termination_se) {
99340024Sgibbs	default:
994241588Sjhb		device_printf(adw->device,
995241588Sjhb		    "Invalid SE EEPROM Termination Settings.\n");
996241588Sjhb		device_printf(adw->device,
997241588Sjhb		    "Reverting to Automatic SE Termination\n");
99840024Sgibbs		/* FALLTHROUGH */
99940024Sgibbs	case ADW_EEPROM_TERM_AUTO:
100040024Sgibbs		break;
100140024Sgibbs	case ADW_EEPROM_TERM_BOTH_ON:
100240024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L;
100340024Sgibbs		/* FALLTHROUGH */
100440024Sgibbs	case ADW_EEPROM_TERM_HIGH_ON:
100540024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H;
100640024Sgibbs		/* FALLTHROUGH */
100740024Sgibbs	case ADW_EEPROM_TERM_OFF:
100840024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL;
100940024Sgibbs		break;
101040024Sgibbs	}
1011241588Sjhb	device_printf(adw->device, "SCSI ID %d, ", adw->initiator_id);
101240024Sgibbs
101340024Sgibbs	/* DMA tag for mapping buffers into device visible space. */
1014112782Smdodd	if (bus_dma_tag_create(
1015112782Smdodd			/* parent	*/ adw->parent_dmat,
1016112782Smdodd			/* alignment	*/ 1,
1017112782Smdodd			/* boundary	*/ 0,
1018112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
1019112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1020112782Smdodd			/* filter	*/ NULL,
1021112782Smdodd			/* filterarg	*/ NULL,
1022112782Smdodd			/* maxsize	*/ MAXBSIZE,
1023112782Smdodd			/* nsegments	*/ ADW_SGSIZE,
1024112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1025112782Smdodd			/* flags	*/ BUS_DMA_ALLOCNOW,
1026117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1027241588Sjhb			/* lockarg	*/ &adw->lock,
1028112782Smdodd			&adw->buffer_dmat) != 0) {
102956979Sgibbs		return (ENOMEM);
103040024Sgibbs	}
103140024Sgibbs
103240024Sgibbs	adw->init_level++;
103340024Sgibbs
103456979Sgibbs	/* DMA tag for our ccb carrier structures */
1035112782Smdodd	if (bus_dma_tag_create(
1036112782Smdodd			/* parent	*/ adw->parent_dmat,
1037112782Smdodd			/* alignment	*/ 0x10,
1038112782Smdodd			/* boundary	*/ 0,
1039112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
1040112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1041112782Smdodd			/* filter	*/ NULL,
1042112782Smdodd			/* filterarg	*/ NULL,
1043112782Smdodd			/* maxsize	*/ (adw->max_acbs +
1044112782Smdodd					    ADW_NUM_CARRIER_QUEUES + 1) *
1045112782Smdodd					    sizeof(struct adw_carrier),
1046112782Smdodd			/* nsegments	*/ 1,
1047112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1048112782Smdodd			/* flags	*/ 0,
1049241588Sjhb			/* lockfunc	*/ NULL,
1050241588Sjhb			/* lockarg	*/ NULL,
1051112782Smdodd			&adw->carrier_dmat) != 0) {
105256979Sgibbs		return (ENOMEM);
105356979Sgibbs        }
105456979Sgibbs
105556979Sgibbs	adw->init_level++;
105656979Sgibbs
105756979Sgibbs	/* Allocation for our ccb carrier structures */
105856979Sgibbs	if (bus_dmamem_alloc(adw->carrier_dmat, (void **)&adw->carriers,
105956979Sgibbs			     BUS_DMA_NOWAIT, &adw->carrier_dmamap) != 0) {
106056979Sgibbs		return (ENOMEM);
106156979Sgibbs	}
106256979Sgibbs
106356979Sgibbs	adw->init_level++;
106456979Sgibbs
106556979Sgibbs	/* And permanently map them */
106656979Sgibbs	bus_dmamap_load(adw->carrier_dmat, adw->carrier_dmamap,
106756979Sgibbs			adw->carriers,
106856979Sgibbs			(adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
106956979Sgibbs			 * sizeof(struct adw_carrier),
107056979Sgibbs			adwmapmem, &adw->carrier_busbase, /*flags*/0);
107156979Sgibbs
107256979Sgibbs	/* Clear them out. */
107356979Sgibbs	bzero(adw->carriers, (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
107456979Sgibbs			     * sizeof(struct adw_carrier));
107556979Sgibbs
107656979Sgibbs	/* Setup our free carrier list */
107756979Sgibbs	adw->free_carriers = adw->carriers;
107856979Sgibbs	for (i = 0; i < adw->max_acbs + ADW_NUM_CARRIER_QUEUES; i++) {
107956979Sgibbs		adw->carriers[i].carr_offset =
108056979Sgibbs			carriervtobo(adw, &adw->carriers[i]);
108156979Sgibbs		adw->carriers[i].carr_ba =
108256979Sgibbs			carriervtob(adw, &adw->carriers[i]);
108356979Sgibbs		adw->carriers[i].areq_ba = 0;
108456979Sgibbs		adw->carriers[i].next_ba =
108556979Sgibbs			carriervtobo(adw, &adw->carriers[i+1]);
108656979Sgibbs	}
108756979Sgibbs	/* Terminal carrier.  Never leaves the freelist */
108856979Sgibbs	adw->carriers[i].carr_offset =
108956979Sgibbs		carriervtobo(adw, &adw->carriers[i]);
109056979Sgibbs	adw->carriers[i].carr_ba =
109156979Sgibbs		carriervtob(adw, &adw->carriers[i]);
109256979Sgibbs	adw->carriers[i].areq_ba = 0;
109356979Sgibbs	adw->carriers[i].next_ba = ~0;
109456979Sgibbs
109556979Sgibbs	adw->init_level++;
109656979Sgibbs
109756979Sgibbs	/* DMA tag for our acb structures */
1098112782Smdodd	if (bus_dma_tag_create(
1099112782Smdodd			/* parent	*/ adw->parent_dmat,
1100112782Smdodd			/* alignment	*/ 1,
1101112782Smdodd			/* boundary	*/ 0,
1102112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1103112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1104112782Smdodd			/* filter	*/ NULL,
1105112782Smdodd			/* filterarg	*/ NULL,
1106112782Smdodd			/* maxsize	*/ adw->max_acbs * sizeof(struct acb),
1107112782Smdodd			/* nsegments	*/ 1,
1108112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1109112782Smdodd			/* flags	*/ 0,
1110241588Sjhb			/* lockfunc	*/ NULL,
1111241588Sjhb			/* lockarg	*/ NULL,
1112112782Smdodd			&adw->acb_dmat) != 0) {
111356979Sgibbs		return (ENOMEM);
111440024Sgibbs        }
111540024Sgibbs
111640024Sgibbs	adw->init_level++;
111740024Sgibbs
111840024Sgibbs	/* Allocation for our ccbs */
111940024Sgibbs	if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs,
112056979Sgibbs			     BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0)
112156979Sgibbs		return (ENOMEM);
112240024Sgibbs
112340024Sgibbs	adw->init_level++;
112440024Sgibbs
112540024Sgibbs	/* And permanently map them */
112640024Sgibbs	bus_dmamap_load(adw->acb_dmat, adw->acb_dmamap,
112740024Sgibbs			adw->acbs,
112840024Sgibbs			adw->max_acbs * sizeof(struct acb),
112940024Sgibbs			adwmapmem, &adw->acb_busbase, /*flags*/0);
113040024Sgibbs
113140024Sgibbs	/* Clear them out. */
113240024Sgibbs	bzero(adw->acbs, adw->max_acbs * sizeof(struct acb));
113340024Sgibbs
113440024Sgibbs	/* DMA tag for our S/G structures.  We allocate in page sized chunks */
1135112782Smdodd	if (bus_dma_tag_create(
1136112782Smdodd			/* parent	*/ adw->parent_dmat,
1137112782Smdodd			/* alignment	*/ 1,
1138112782Smdodd			/* boundary	*/ 0,
1139112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1140112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1141112782Smdodd			/* filter	*/ NULL,
1142112782Smdodd			/* filterarg	*/ NULL,
1143112782Smdodd			/* maxsize	*/ PAGE_SIZE,
1144112782Smdodd			/* nsegments	*/ 1,
1145112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1146112782Smdodd			/* flags	*/ 0,
1147241588Sjhb			/* lockfunc	*/ NULL,
1148241588Sjhb			/* lockarg	*/ NULL,
1149112782Smdodd			&adw->sg_dmat) != 0) {
115056979Sgibbs		return (ENOMEM);
115140024Sgibbs        }
115240024Sgibbs
115340024Sgibbs	adw->init_level++;
115440024Sgibbs
115540024Sgibbs	/* Allocate our first batch of ccbs */
1156241588Sjhb	mtx_lock(&adw->lock);
1157241588Sjhb	if (adwallocacbs(adw) == 0) {
1158241588Sjhb		mtx_unlock(&adw->lock);
115956979Sgibbs		return (ENOMEM);
1160241588Sjhb	}
116140024Sgibbs
1162241588Sjhb	if (adw_init_chip(adw, scsicfg1) != 0) {
1163241588Sjhb		mtx_unlock(&adw->lock);
116456979Sgibbs		return (ENXIO);
1165241588Sjhb	}
116656979Sgibbs
116756979Sgibbs	printf("Queue Depth %d\n", adw->max_acbs);
1168241588Sjhb	mtx_unlock(&adw->lock);
116956979Sgibbs
117040024Sgibbs	return (0);
117140024Sgibbs}
117240024Sgibbs
117340024Sgibbs/*
117440024Sgibbs * Attach all the sub-devices we can find
117540024Sgibbs */
117640024Sgibbsint
117740024Sgibbsadw_attach(struct adw_softc *adw)
117840024Sgibbs{
117940024Sgibbs	struct ccb_setasync csa;
118040024Sgibbs	struct cam_devq *devq;
118156979Sgibbs	int error;
118240024Sgibbs
118356979Sgibbs	/* Hook up our interrupt handler */
1184241588Sjhb	error = bus_setup_intr(adw->device, adw->irq,
1185241588Sjhb	    INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE, NULL, adw_intr, adw,
1186241588Sjhb	    &adw->ih);
1187241588Sjhb	if (error != 0) {
118856979Sgibbs		device_printf(adw->device, "bus_setup_intr() failed: %d\n",
118956979Sgibbs			      error);
1190241588Sjhb		return (error);
119156979Sgibbs	}
119256979Sgibbs
119340024Sgibbs	/* Start the Risc processor now that we are fully configured. */
119440024Sgibbs	adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN);
119540024Sgibbs
119640024Sgibbs	/*
119740024Sgibbs	 * Create the device queue for our SIM.
119840024Sgibbs	 */
119940024Sgibbs	devq = cam_simq_alloc(adw->max_acbs);
120040024Sgibbs	if (devq == NULL)
120156979Sgibbs		return (ENOMEM);
120240024Sgibbs
120340024Sgibbs	/*
120440024Sgibbs	 * Construct our SIM entry.
120540024Sgibbs	 */
1206241588Sjhb	adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw,
1207241588Sjhb	    device_get_unit(adw->device), &adw->lock, 1, adw->max_acbs, devq);
1208241588Sjhb	if (adw->sim == NULL)
1209241588Sjhb		return (ENOMEM);
121040024Sgibbs
121140024Sgibbs	/*
121240024Sgibbs	 * Register the bus.
121340024Sgibbs	 */
1214241588Sjhb	mtx_lock(&adw->lock);
1215170872Sscottl	if (xpt_bus_register(adw->sim, adw->device, 0) != CAM_SUCCESS) {
121640024Sgibbs		cam_sim_free(adw->sim, /*free devq*/TRUE);
121756979Sgibbs		error = ENOMEM;
121856979Sgibbs		goto fail;
121940024Sgibbs	}
122040024Sgibbs
122140024Sgibbs	if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim),
122240024Sgibbs			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
122340024Sgibbs	   == CAM_REQ_CMP) {
122440024Sgibbs		xpt_setup_ccb(&csa.ccb_h, adw->path, /*priority*/5);
122540024Sgibbs		csa.ccb_h.func_code = XPT_SASYNC_CB;
122640024Sgibbs		csa.event_enable = AC_LOST_DEVICE;
122740024Sgibbs		csa.callback = adw_async;
122840024Sgibbs		csa.callback_arg = adw;
122940024Sgibbs		xpt_action((union ccb *)&csa);
123040024Sgibbs	}
123140024Sgibbs
123256979Sgibbsfail:
1233241588Sjhb	mtx_unlock(&adw->lock);
123456979Sgibbs	return (error);
123540024Sgibbs}
123640024Sgibbs
123740024Sgibbsvoid
123840024Sgibbsadw_intr(void *arg)
123940024Sgibbs{
124040024Sgibbs	struct	adw_softc *adw;
1241241588Sjhb
1242241588Sjhb	adw = arg;
1243241588Sjhb	mtx_lock(&adw->lock);
1244241588Sjhb	adw_intr_locked(adw);
1245241588Sjhb	mtx_unlock(&adw->lock);
1246241588Sjhb}
1247241588Sjhb
1248241588Sjhbvoid
1249241588Sjhbadw_intr_locked(struct adw_softc *adw)
1250241588Sjhb{
125140024Sgibbs	u_int	int_stat;
125240024Sgibbs
125340024Sgibbs	if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0)
125440024Sgibbs		return;
125540024Sgibbs
125640024Sgibbs	/* Reading the register clears the interrupt. */
125740024Sgibbs	int_stat = adw_inb(adw, ADW_INTR_STATUS_REG);
125840024Sgibbs
125940024Sgibbs	if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) {
126056979Sgibbs		u_int intrb_code;
126156979Sgibbs
126256979Sgibbs		/* Async Microcode Event */
126356979Sgibbs		intrb_code = adw_lram_read_8(adw, ADW_MC_INTRB_CODE);
126456979Sgibbs		switch (intrb_code) {
126556979Sgibbs		case ADW_ASYNC_CARRIER_READY_FAILURE:
126656979Sgibbs			/*
126756979Sgibbs			 * The RISC missed our update of
126856979Sgibbs			 * the commandq.
126956979Sgibbs			 */
127056979Sgibbs			if (LIST_FIRST(&adw->pending_ccbs) != NULL)
127156979Sgibbs				adw_tickle_risc(adw, ADW_TICKLE_A);
127240024Sgibbs			break;
127356979Sgibbs    		case ADW_ASYNC_SCSI_BUS_RESET_DET:
127456979Sgibbs			/*
127556979Sgibbs			 * The firmware detected a SCSI Bus reset.
127656979Sgibbs			 */
1277241588Sjhb			device_printf(adw->device, "Someone Reset the Bus\n");
127856979Sgibbs			adw_handle_bus_reset(adw, /*initiated*/FALSE);
127956979Sgibbs			break;
128056979Sgibbs		case ADW_ASYNC_RDMA_FAILURE:
128156979Sgibbs			/*
128256979Sgibbs			 * Handle RDMA failure by resetting the
128356979Sgibbs			 * SCSI Bus and chip.
128456979Sgibbs			 */
1285153072Sru#if 0 /* XXX */
128656979Sgibbs			AdvResetChipAndSB(adv_dvc_varp);
128756979Sgibbs#endif
128856979Sgibbs			break;
128956979Sgibbs
129056979Sgibbs		case ADW_ASYNC_HOST_SCSI_BUS_RESET:
129156979Sgibbs			/*
129256979Sgibbs			 * Host generated SCSI bus reset occurred.
129356979Sgibbs			 */
129440024Sgibbs			adw_handle_bus_reset(adw, /*initiated*/TRUE);
129556979Sgibbs        		break;
129656979Sgibbs    		default:
129756979Sgibbs			printf("adw_intr: unknown async code 0x%x\n",
129856979Sgibbs			       intrb_code);
129940024Sgibbs			break;
130040024Sgibbs		}
130140024Sgibbs	}
130240024Sgibbs
130340024Sgibbs	/*
130456979Sgibbs	 * Run down the RequestQ.
130540024Sgibbs	 */
130656979Sgibbs	while ((adw->responseq->next_ba & ADW_RQ_DONE) != 0) {
130756979Sgibbs		struct adw_carrier *free_carrier;
130856979Sgibbs		struct acb *acb;
130956979Sgibbs		union ccb *ccb;
131040024Sgibbs
131156979Sgibbs#if 0
131256979Sgibbs		printf("0x%x, 0x%x, 0x%x, 0x%x\n",
131356979Sgibbs		       adw->responseq->carr_offset,
131456979Sgibbs		       adw->responseq->carr_ba,
131556979Sgibbs		       adw->responseq->areq_ba,
131656979Sgibbs		       adw->responseq->next_ba);
131756979Sgibbs#endif
131856979Sgibbs		/*
131956979Sgibbs		 * The firmware copies the adw_scsi_req_q.acb_baddr
132056979Sgibbs		 * field into the areq_ba field of the carrier.
132156979Sgibbs		 */
132256979Sgibbs		acb = acbbotov(adw, adw->responseq->areq_ba);
132340024Sgibbs
132440024Sgibbs		/*
132556979Sgibbs		 * The least significant four bits of the next_ba
132656979Sgibbs		 * field are used as flags.  Mask them out and then
132756979Sgibbs		 * advance through the list.
132840024Sgibbs		 */
132956979Sgibbs		free_carrier = adw->responseq;
133056979Sgibbs		adw->responseq =
133156979Sgibbs		    carrierbotov(adw, free_carrier->next_ba & ADW_NEXT_BA_MASK);
133256979Sgibbs		free_carrier->next_ba = adw->free_carriers->carr_offset;
133356979Sgibbs		adw->free_carriers = free_carrier;
133440024Sgibbs
133540024Sgibbs		/* Process CCB */
133640024Sgibbs		ccb = acb->ccb;
1337241588Sjhb		callout_stop(&acb->timer);
133840024Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
1339115343Sscottl			bus_dmasync_op_t op;
134040024Sgibbs
134140024Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
134240024Sgibbs				op = BUS_DMASYNC_POSTREAD;
134340024Sgibbs			else
134440024Sgibbs				op = BUS_DMASYNC_POSTWRITE;
134540024Sgibbs			bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
134640024Sgibbs			bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
134740024Sgibbs			ccb->csio.resid = acb->queue.data_cnt;
134840024Sgibbs		} else
134940024Sgibbs			ccb->csio.resid = 0;
135040024Sgibbs
135140024Sgibbs		/* Common Cases inline... */
135240024Sgibbs		if (acb->queue.host_status == QHSTA_NO_ERROR
135340024Sgibbs		 && (acb->queue.done_status == QD_NO_ERROR
135440024Sgibbs		  || acb->queue.done_status == QD_WITH_ERROR)) {
135540024Sgibbs			ccb->csio.scsi_status = acb->queue.scsi_status;
135640024Sgibbs			ccb->ccb_h.status = 0;
135740024Sgibbs			switch (ccb->csio.scsi_status) {
135840024Sgibbs			case SCSI_STATUS_OK:
135940024Sgibbs				ccb->ccb_h.status |= CAM_REQ_CMP;
136040024Sgibbs				break;
136140024Sgibbs			case SCSI_STATUS_CHECK_COND:
136240024Sgibbs			case SCSI_STATUS_CMD_TERMINATED:
136340024Sgibbs				bcopy(&acb->sense_data, &ccb->csio.sense_data,
136440024Sgibbs				      ccb->csio.sense_len);
136540024Sgibbs				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
136640024Sgibbs				ccb->csio.sense_resid = acb->queue.sense_len;
136740024Sgibbs				/* FALLTHROUGH */
136840024Sgibbs			default:
136940024Sgibbs				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR
137040024Sgibbs						  |  CAM_DEV_QFRZN;
137140024Sgibbs				xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
137240024Sgibbs				break;
137340024Sgibbs			}
137440024Sgibbs			adwfreeacb(adw, acb);
137540024Sgibbs			xpt_done(ccb);
137640024Sgibbs		} else {
137740024Sgibbs			adwprocesserror(adw, acb);
137840024Sgibbs		}
137940024Sgibbs	}
138040024Sgibbs}
138140024Sgibbs
138240024Sgibbsstatic void
138340024Sgibbsadwprocesserror(struct adw_softc *adw, struct acb *acb)
138440024Sgibbs{
138540024Sgibbs	union ccb *ccb;
138640024Sgibbs
138740024Sgibbs	ccb = acb->ccb;
138840024Sgibbs	if (acb->queue.done_status == QD_ABORTED_BY_HOST) {
138940024Sgibbs		ccb->ccb_h.status = CAM_REQ_ABORTED;
139040024Sgibbs	} else {
139140024Sgibbs
139240024Sgibbs		switch (acb->queue.host_status) {
139340024Sgibbs		case QHSTA_M_SEL_TIMEOUT:
139440024Sgibbs			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
139540024Sgibbs			break;
139640024Sgibbs		case QHSTA_M_SXFR_OFF_UFLW:
139740024Sgibbs		case QHSTA_M_SXFR_OFF_OFLW:
139840024Sgibbs		case QHSTA_M_DATA_OVER_RUN:
139940024Sgibbs			ccb->ccb_h.status = CAM_DATA_RUN_ERR;
140040024Sgibbs			break;
140140024Sgibbs		case QHSTA_M_SXFR_DESELECTED:
140240024Sgibbs		case QHSTA_M_UNEXPECTED_BUS_FREE:
140340024Sgibbs			ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
140440024Sgibbs			break;
140557679Sgibbs		case QHSTA_M_SCSI_BUS_RESET:
140657679Sgibbs		case QHSTA_M_SCSI_BUS_RESET_UNSOL:
140757679Sgibbs			ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
140857679Sgibbs			break;
140957679Sgibbs		case QHSTA_M_BUS_DEVICE_RESET:
141057679Sgibbs			ccb->ccb_h.status = CAM_BDR_SENT;
141157679Sgibbs			break;
141240024Sgibbs		case QHSTA_M_QUEUE_ABORTED:
141340024Sgibbs			/* BDR or Bus Reset */
1414241588Sjhb			xpt_print_path(adw->path);
141557679Sgibbs			printf("Saw Queue Aborted\n");
141640024Sgibbs			ccb->ccb_h.status = adw->last_reset;
141740024Sgibbs			break;
141840024Sgibbs		case QHSTA_M_SXFR_SDMA_ERR:
141940024Sgibbs		case QHSTA_M_SXFR_SXFR_PERR:
142040024Sgibbs		case QHSTA_M_RDMA_PERR:
142140024Sgibbs			ccb->ccb_h.status = CAM_UNCOR_PARITY;
142240024Sgibbs			break;
142340024Sgibbs		case QHSTA_M_WTM_TIMEOUT:
142440024Sgibbs		case QHSTA_M_SXFR_WD_TMO:
142556979Sgibbs		{
142640024Sgibbs			/* The SCSI bus hung in a phase */
142757679Sgibbs			xpt_print_path(adw->path);
1428241588Sjhb			printf("Watch Dog timer expired.  Resetting bus\n");
142957679Sgibbs			adw_reset_bus(adw);
143040024Sgibbs			break;
143156979Sgibbs		}
143240024Sgibbs		case QHSTA_M_SXFR_XFR_PH_ERR:
143340024Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
143440024Sgibbs			break;
143540024Sgibbs		case QHSTA_M_SXFR_UNKNOWN_ERROR:
143640024Sgibbs			break;
143740024Sgibbs		case QHSTA_M_BAD_CMPL_STATUS_IN:
143840024Sgibbs			/* No command complete after a status message */
143940024Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
144040024Sgibbs			break;
144140024Sgibbs		case QHSTA_M_AUTO_REQ_SENSE_FAIL:
144240024Sgibbs			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
144340024Sgibbs			break;
144440024Sgibbs		case QHSTA_M_INVALID_DEVICE:
144540024Sgibbs			ccb->ccb_h.status = CAM_PATH_INVALID;
144640024Sgibbs			break;
144740024Sgibbs		case QHSTA_M_NO_AUTO_REQ_SENSE:
144840024Sgibbs			/*
144940024Sgibbs			 * User didn't request sense, but we got a
145040024Sgibbs			 * check condition.
145140024Sgibbs			 */
145240024Sgibbs			ccb->csio.scsi_status = acb->queue.scsi_status;
145340024Sgibbs			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
145440024Sgibbs			break;
145540024Sgibbs		default:
145640024Sgibbs			panic("%s: Unhandled Host status error %x",
1457241588Sjhb			    device_get_nameunit(adw->device),
1458241588Sjhb			    acb->queue.host_status);
145940024Sgibbs			/* NOTREACHED */
146040024Sgibbs		}
146140024Sgibbs	}
146257679Sgibbs	if ((acb->state & ACB_RECOVERY_ACB) != 0) {
146357679Sgibbs		if (ccb->ccb_h.status == CAM_SCSI_BUS_RESET
146457679Sgibbs		 || ccb->ccb_h.status == CAM_BDR_SENT)
146557679Sgibbs		 	ccb->ccb_h.status = CAM_CMD_TIMEOUT;
146657679Sgibbs	}
146740024Sgibbs	if (ccb->ccb_h.status != CAM_REQ_CMP) {
146840024Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
146940024Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
147040024Sgibbs	}
147140024Sgibbs	adwfreeacb(adw, acb);
147240024Sgibbs	xpt_done(ccb);
147340024Sgibbs}
147440024Sgibbs
147540024Sgibbsstatic void
147640024Sgibbsadwtimeout(void *arg)
147740024Sgibbs{
147840024Sgibbs	struct acb	     *acb;
147940024Sgibbs	union  ccb	     *ccb;
148040024Sgibbs	struct adw_softc     *adw;
148140024Sgibbs	adw_idle_cmd_status_t status;
148257679Sgibbs	int		      target_id;
148340024Sgibbs
148440024Sgibbs	acb = (struct acb *)arg;
148540024Sgibbs	ccb = acb->ccb;
148640024Sgibbs	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
148740024Sgibbs	xpt_print_path(ccb->ccb_h.path);
148840024Sgibbs	printf("ACB %p - timed out\n", (void *)acb);
148940024Sgibbs
1490241588Sjhb	mtx_assert(&adw->lock, MA_OWNED);
149140024Sgibbs
149240024Sgibbs	if ((acb->state & ACB_ACTIVE) == 0) {
149340024Sgibbs		xpt_print_path(ccb->ccb_h.path);
149440024Sgibbs		printf("ACB %p - timed out CCB already completed\n",
149540024Sgibbs		       (void *)acb);
149640024Sgibbs		return;
149740024Sgibbs	}
149840024Sgibbs
149957679Sgibbs	acb->state |= ACB_RECOVERY_ACB;
150057679Sgibbs	target_id = ccb->ccb_h.target_id;
150157679Sgibbs
150240024Sgibbs	/* Attempt a BDR first */
150357679Sgibbs	status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
150457679Sgibbs				   ccb->ccb_h.target_id);
150540024Sgibbs	if (status == ADW_IDLE_CMD_SUCCESS) {
1506241588Sjhb		device_printf(adw->device,
1507241588Sjhb		    "BDR Delivered.  No longer in timeout\n");
150857679Sgibbs		adw_handle_device_reset(adw, target_id);
150940024Sgibbs	} else {
151057679Sgibbs		adw_reset_bus(adw);
151157679Sgibbs		xpt_print_path(adw->path);
151257679Sgibbs		printf("Bus Reset Delivered.  No longer in timeout\n");
151340024Sgibbs	}
151440024Sgibbs}
151540024Sgibbs
151640024Sgibbsstatic void
151740024Sgibbsadw_handle_device_reset(struct adw_softc *adw, u_int target)
151840024Sgibbs{
151940024Sgibbs	struct cam_path *path;
152040024Sgibbs	cam_status error;
152140024Sgibbs
152240024Sgibbs	error = xpt_create_path(&path, /*periph*/NULL, cam_sim_path(adw->sim),
152340024Sgibbs				target, CAM_LUN_WILDCARD);
152440024Sgibbs
152540024Sgibbs	if (error == CAM_REQ_CMP) {
152640024Sgibbs		xpt_async(AC_SENT_BDR, path, NULL);
152740024Sgibbs		xpt_free_path(path);
152840024Sgibbs	}
152940024Sgibbs	adw->last_reset = CAM_BDR_SENT;
153040024Sgibbs}
153140024Sgibbs
153240024Sgibbsstatic void
153340024Sgibbsadw_handle_bus_reset(struct adw_softc *adw, int initiated)
153440024Sgibbs{
153540024Sgibbs	if (initiated) {
153640024Sgibbs		/*
153740024Sgibbs		 * The microcode currently sets the SCSI Bus Reset signal
153840024Sgibbs		 * while handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET
153940024Sgibbs		 * command above.  But the SCSI Bus Reset Hold Time in the
154040024Sgibbs		 * microcode is not deterministic (it may in fact be for less
154140024Sgibbs		 * than the SCSI Spec. minimum of 25 us).  Therefore on return
154240024Sgibbs		 * the Adv Library sets the SCSI Bus Reset signal for
154340024Sgibbs		 * ADW_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
154440024Sgibbs		 * than 25 us.
154540024Sgibbs		 */
154640024Sgibbs		u_int scsi_ctrl;
154740024Sgibbs
154840024Sgibbs	    	scsi_ctrl = adw_inw(adw, ADW_SCSI_CTRL) & ~ADW_SCSI_CTRL_RSTOUT;
154940024Sgibbs		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl | ADW_SCSI_CTRL_RSTOUT);
155040024Sgibbs		DELAY(ADW_SCSI_RESET_HOLD_TIME_US);
155140024Sgibbs		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl);
155240024Sgibbs
155340024Sgibbs		/*
155440024Sgibbs		 * We will perform the async notification when the
155540024Sgibbs		 * SCSI Reset interrupt occurs.
155640024Sgibbs		 */
155740024Sgibbs	} else
155840024Sgibbs		xpt_async(AC_BUS_RESET, adw->path, NULL);
155940024Sgibbs	adw->last_reset = CAM_SCSI_BUS_RESET;
156040024Sgibbs}
1561165102SmjacobMODULE_DEPEND(adw, cam, 1, 1, 1);
1562165102Smjacob
1563