adwcam.c revision 138502
140024Sgibbs/*
240024Sgibbs * CAM SCSI interface for the 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 138502 2004-12-06 23:17:04Z rsm $");
48119418Sobrien
4940024Sgibbs#include <sys/param.h>
5040024Sgibbs#include <sys/systm.h>
5140024Sgibbs#include <sys/kernel.h>
5240024Sgibbs#include <sys/malloc.h>
53117126Sscottl#include <sys/lock.h>
54117126Sscottl#include <sys/mutex.h>
5556979Sgibbs#include <sys/bus.h>
5640024Sgibbs
5740024Sgibbs#include <machine/bus_pio.h>
5840024Sgibbs#include <machine/bus_memio.h>
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
7840024Sgibbsu_long adw_unit;
7940024Sgibbs
8057679Sgibbsstatic __inline cam_status	adwccbstatus(union ccb*);
8140024Sgibbsstatic __inline struct acb*	adwgetacb(struct adw_softc *adw);
8240024Sgibbsstatic __inline void		adwfreeacb(struct adw_softc *adw,
8340024Sgibbs					   struct acb *acb);
8440024Sgibbs
8540024Sgibbsstatic void		adwmapmem(void *arg, bus_dma_segment_t *segs,
8640024Sgibbs				  int nseg, int error);
8740024Sgibbsstatic struct sg_map_node*
8840024Sgibbs			adwallocsgmap(struct adw_softc *adw);
8940024Sgibbsstatic int		adwallocacbs(struct adw_softc *adw);
9040024Sgibbs
9140024Sgibbsstatic void		adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs,
9240024Sgibbs				      int nseg, int error);
9340024Sgibbsstatic void		adw_action(struct cam_sim *sim, union ccb *ccb);
9440024Sgibbsstatic void		adw_poll(struct cam_sim *sim);
9540024Sgibbsstatic void		adw_async(void *callback_arg, u_int32_t code,
9640024Sgibbs				  struct cam_path *path, void *arg);
9740024Sgibbsstatic void		adwprocesserror(struct adw_softc *adw, struct acb *acb);
9840024Sgibbsstatic void		adwtimeout(void *arg);
9940024Sgibbsstatic void		adw_handle_device_reset(struct adw_softc *adw,
10040024Sgibbs						u_int target);
10140024Sgibbsstatic void		adw_handle_bus_reset(struct adw_softc *adw,
10240024Sgibbs					     int initiated);
10340024Sgibbs
10457679Sgibbsstatic __inline cam_status
10557679Sgibbsadwccbstatus(union ccb* ccb)
10657679Sgibbs{
10757679Sgibbs	return (ccb->ccb_h.status & CAM_STATUS_MASK);
10857679Sgibbs}
10957679Sgibbs
11040024Sgibbsstatic __inline struct acb*
11140024Sgibbsadwgetacb(struct adw_softc *adw)
11240024Sgibbs{
11340024Sgibbs	struct	acb* acb;
11440024Sgibbs	int	s;
11540024Sgibbs
11640024Sgibbs	s = splcam();
11740024Sgibbs	if ((acb = SLIST_FIRST(&adw->free_acb_list)) != NULL) {
11840024Sgibbs		SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
11940024Sgibbs	} else if (adw->num_acbs < adw->max_acbs) {
12040024Sgibbs		adwallocacbs(adw);
12140024Sgibbs		acb = SLIST_FIRST(&adw->free_acb_list);
12240024Sgibbs		if (acb == NULL)
12340024Sgibbs			printf("%s: Can't malloc ACB\n", adw_name(adw));
12440024Sgibbs		else {
12540024Sgibbs			SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
12640024Sgibbs		}
12740024Sgibbs	}
12840024Sgibbs	splx(s);
12940024Sgibbs
13040024Sgibbs	return (acb);
13140024Sgibbs}
13240024Sgibbs
13340024Sgibbsstatic __inline void
13440024Sgibbsadwfreeacb(struct adw_softc *adw, struct acb *acb)
13540024Sgibbs{
13640024Sgibbs	int s;
13740024Sgibbs
13840024Sgibbs	s = splcam();
13940024Sgibbs	if ((acb->state & ACB_ACTIVE) != 0)
14040024Sgibbs		LIST_REMOVE(&acb->ccb->ccb_h, sim_links.le);
14140024Sgibbs	if ((acb->state & ACB_RELEASE_SIMQ) != 0)
14240024Sgibbs		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
14340024Sgibbs	else if ((adw->state & ADW_RESOURCE_SHORTAGE) != 0
14440024Sgibbs	      && (acb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
14540024Sgibbs		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
14640024Sgibbs		adw->state &= ~ADW_RESOURCE_SHORTAGE;
14740024Sgibbs	}
14840024Sgibbs	acb->state = ACB_FREE;
14940024Sgibbs	SLIST_INSERT_HEAD(&adw->free_acb_list, acb, links);
15040024Sgibbs	splx(s);
15140024Sgibbs}
15240024Sgibbs
15340024Sgibbsstatic void
15440024Sgibbsadwmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
15540024Sgibbs{
15640024Sgibbs	bus_addr_t *busaddrp;
15740024Sgibbs
15840024Sgibbs	busaddrp = (bus_addr_t *)arg;
15940024Sgibbs	*busaddrp = segs->ds_addr;
16040024Sgibbs}
16140024Sgibbs
16240024Sgibbsstatic struct sg_map_node *
16340024Sgibbsadwallocsgmap(struct adw_softc *adw)
16440024Sgibbs{
16540024Sgibbs	struct sg_map_node *sg_map;
16640024Sgibbs
16740024Sgibbs	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
16840024Sgibbs
16940024Sgibbs	if (sg_map == NULL)
17040024Sgibbs		return (NULL);
17140024Sgibbs
17240024Sgibbs	/* Allocate S/G space for the next batch of ACBS */
17340024Sgibbs	if (bus_dmamem_alloc(adw->sg_dmat, (void **)&sg_map->sg_vaddr,
17440024Sgibbs			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
17540024Sgibbs		free(sg_map, M_DEVBUF);
17640024Sgibbs		return (NULL);
17740024Sgibbs	}
17840024Sgibbs
17940024Sgibbs	SLIST_INSERT_HEAD(&adw->sg_maps, sg_map, links);
18040024Sgibbs
18140024Sgibbs	bus_dmamap_load(adw->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
18240024Sgibbs			PAGE_SIZE, adwmapmem, &sg_map->sg_physaddr, /*flags*/0);
18340024Sgibbs
18440024Sgibbs	bzero(sg_map->sg_vaddr, PAGE_SIZE);
18540024Sgibbs	return (sg_map);
18640024Sgibbs}
18740024Sgibbs
18840024Sgibbs/*
18940024Sgibbs * Allocate another chunk of CCB's. Return count of entries added.
19040024Sgibbs * Assumed to be called at splcam().
19140024Sgibbs */
19240024Sgibbsstatic int
19340024Sgibbsadwallocacbs(struct adw_softc *adw)
19440024Sgibbs{
19540024Sgibbs	struct acb *next_acb;
19640024Sgibbs	struct sg_map_node *sg_map;
19740024Sgibbs	bus_addr_t busaddr;
19840024Sgibbs	struct adw_sg_block *blocks;
19940024Sgibbs	int newcount;
20040024Sgibbs	int i;
20140024Sgibbs
20240024Sgibbs	next_acb = &adw->acbs[adw->num_acbs];
20340024Sgibbs	sg_map = adwallocsgmap(adw);
20440024Sgibbs
20540024Sgibbs	if (sg_map == NULL)
20640024Sgibbs		return (0);
20740024Sgibbs
20840024Sgibbs	blocks = sg_map->sg_vaddr;
20940024Sgibbs	busaddr = sg_map->sg_physaddr;
21040024Sgibbs
21140024Sgibbs	newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks)));
21240024Sgibbs	for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) {
21340024Sgibbs		int error;
21440024Sgibbs
21540024Sgibbs		error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0,
21640024Sgibbs					  &next_acb->dmamap);
21740024Sgibbs		if (error != 0)
21840024Sgibbs			break;
21956979Sgibbs		next_acb->queue.scsi_req_baddr = acbvtob(adw, next_acb);
22056979Sgibbs		next_acb->queue.scsi_req_bo = acbvtobo(adw, next_acb);
22156979Sgibbs		next_acb->queue.sense_baddr =
22256979Sgibbs		    acbvtob(adw, next_acb) + offsetof(struct acb, sense_data);
22340024Sgibbs		next_acb->sg_blocks = blocks;
22440024Sgibbs		next_acb->sg_busaddr = busaddr;
22540024Sgibbs		next_acb->state = ACB_FREE;
22640024Sgibbs		SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links);
22740024Sgibbs		blocks += ADW_SG_BLOCKCNT;
22840024Sgibbs		busaddr += ADW_SG_BLOCKCNT * sizeof(*blocks);
22940024Sgibbs		next_acb++;
23040024Sgibbs		adw->num_acbs++;
23140024Sgibbs	}
23240024Sgibbs	return (i);
23340024Sgibbs}
23440024Sgibbs
23540024Sgibbsstatic void
23640024Sgibbsadwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
23740024Sgibbs{
23840024Sgibbs	struct	 acb *acb;
23940024Sgibbs	union	 ccb *ccb;
24040024Sgibbs	struct	 adw_softc *adw;
24140420Sgibbs	int	 s;
24240024Sgibbs
24340024Sgibbs	acb = (struct acb *)arg;
24440024Sgibbs	ccb = acb->ccb;
24540024Sgibbs	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
24640024Sgibbs
24740024Sgibbs	if (error != 0) {
24840024Sgibbs		if (error != EFBIG)
24940024Sgibbs			printf("%s: Unexepected error 0x%x returned from "
25040024Sgibbs			       "bus_dmamap_load\n", adw_name(adw), error);
25140024Sgibbs		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
25240024Sgibbs			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
25340024Sgibbs			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
25440024Sgibbs		}
25540024Sgibbs		adwfreeacb(adw, acb);
25640024Sgibbs		xpt_done(ccb);
25740024Sgibbs		return;
25840024Sgibbs	}
25940024Sgibbs
26040024Sgibbs	if (nseg != 0) {
261115343Sscottl		bus_dmasync_op_t op;
26240024Sgibbs
26340024Sgibbs		acb->queue.data_addr = dm_segs[0].ds_addr;
26440024Sgibbs		acb->queue.data_cnt = ccb->csio.dxfer_len;
26540024Sgibbs		if (nseg > 1) {
26640024Sgibbs			struct adw_sg_block *sg_block;
26740024Sgibbs			struct adw_sg_elm *sg;
26840024Sgibbs			bus_addr_t sg_busaddr;
26940024Sgibbs			u_int sg_index;
27040024Sgibbs			bus_dma_segment_t *end_seg;
27140024Sgibbs
27240024Sgibbs			end_seg = dm_segs + nseg;
27340024Sgibbs
27440024Sgibbs			sg_busaddr = acb->sg_busaddr;
27540024Sgibbs			sg_index = 0;
27640024Sgibbs			/* Copy the segments into our SG list */
27740024Sgibbs			for (sg_block = acb->sg_blocks;; sg_block++) {
27856979Sgibbs				u_int i;
27940024Sgibbs
28040024Sgibbs				sg = sg_block->sg_list;
28156979Sgibbs				for (i = 0; i < ADW_NO_OF_SG_PER_BLOCK; i++) {
28256979Sgibbs					if (dm_segs >= end_seg)
28356979Sgibbs						break;
28456979Sgibbs
28540024Sgibbs					sg->sg_addr = dm_segs->ds_addr;
28640024Sgibbs					sg->sg_count = dm_segs->ds_len;
28740024Sgibbs					sg++;
28840024Sgibbs					dm_segs++;
28940024Sgibbs				}
29056979Sgibbs				sg_block->sg_cnt = i;
29156979Sgibbs				sg_index += i;
29240024Sgibbs				if (dm_segs == end_seg) {
29340024Sgibbs					sg_block->sg_busaddr_next = 0;
29440024Sgibbs					break;
29540024Sgibbs				} else {
29640024Sgibbs					sg_busaddr +=
29740024Sgibbs					    sizeof(struct adw_sg_block);
29840024Sgibbs					sg_block->sg_busaddr_next = sg_busaddr;
29940024Sgibbs				}
30040024Sgibbs			}
30140024Sgibbs			acb->queue.sg_real_addr = acb->sg_busaddr;
30240024Sgibbs		} else {
30340024Sgibbs			acb->queue.sg_real_addr = 0;
30440024Sgibbs		}
30540024Sgibbs
30640024Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
30740024Sgibbs			op = BUS_DMASYNC_PREREAD;
30840024Sgibbs		else
30940024Sgibbs			op = BUS_DMASYNC_PREWRITE;
31040024Sgibbs
31140024Sgibbs		bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
31240024Sgibbs
31340024Sgibbs	} else {
31440024Sgibbs		acb->queue.data_addr = 0;
31540024Sgibbs		acb->queue.data_cnt = 0;
31640024Sgibbs		acb->queue.sg_real_addr = 0;
31740024Sgibbs	}
31840024Sgibbs
31940024Sgibbs	s = splcam();
32040024Sgibbs
32140024Sgibbs	/*
32240024Sgibbs	 * Last time we need to check if this CCB needs to
32340024Sgibbs	 * be aborted.
32440024Sgibbs	 */
32540024Sgibbs	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
32640024Sgibbs		if (nseg != 0)
32740024Sgibbs			bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
32840024Sgibbs		adwfreeacb(adw, acb);
32940024Sgibbs		xpt_done(ccb);
33040024Sgibbs		splx(s);
33140024Sgibbs		return;
33240024Sgibbs	}
33357679Sgibbs
33440024Sgibbs	acb->state |= ACB_ACTIVE;
33540024Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
33640024Sgibbs	LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le);
33740024Sgibbs	ccb->ccb_h.timeout_ch =
33840024Sgibbs	    timeout(adwtimeout, (caddr_t)acb,
33940024Sgibbs		    (ccb->ccb_h.timeout * hz) / 1000);
34040024Sgibbs
34156979Sgibbs	adw_send_acb(adw, acb, acbvtob(adw, acb));
34240024Sgibbs
34340024Sgibbs	splx(s);
34440024Sgibbs}
34540024Sgibbs
34640024Sgibbsstatic void
34740024Sgibbsadw_action(struct cam_sim *sim, union ccb *ccb)
34840024Sgibbs{
34940024Sgibbs	struct	adw_softc *adw;
35040024Sgibbs
35140024Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adw_action\n"));
35240024Sgibbs
35340024Sgibbs	adw = (struct adw_softc *)cam_sim_softc(sim);
35440024Sgibbs
35540024Sgibbs	switch (ccb->ccb_h.func_code) {
35640024Sgibbs	/* Common cases first */
35740024Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
35840024Sgibbs	{
35940024Sgibbs		struct	ccb_scsiio *csio;
36040024Sgibbs		struct	ccb_hdr *ccbh;
36140024Sgibbs		struct	acb *acb;
36240024Sgibbs
36340024Sgibbs		csio = &ccb->csio;
36440024Sgibbs		ccbh = &ccb->ccb_h;
36556979Sgibbs
36640024Sgibbs		/* Max supported CDB length is 12 bytes */
36740024Sgibbs		if (csio->cdb_len > 12) {
36840024Sgibbs			ccb->ccb_h.status = CAM_REQ_INVALID;
36940024Sgibbs			xpt_done(ccb);
37040024Sgibbs			return;
37140024Sgibbs		}
37240024Sgibbs
37340024Sgibbs		if ((acb = adwgetacb(adw)) == NULL) {
37440024Sgibbs			int s;
37540024Sgibbs
37640024Sgibbs			s = splcam();
37740024Sgibbs			adw->state |= ADW_RESOURCE_SHORTAGE;
37840024Sgibbs			splx(s);
37940024Sgibbs			xpt_freeze_simq(sim, /*count*/1);
38040024Sgibbs			ccb->ccb_h.status = CAM_REQUEUE_REQ;
38140024Sgibbs			xpt_done(ccb);
38240024Sgibbs			return;
38340024Sgibbs		}
38440024Sgibbs
38556979Sgibbs		/* Link acb and ccb so we can find one from the other */
38640024Sgibbs		acb->ccb = ccb;
38740024Sgibbs		ccb->ccb_h.ccb_acb_ptr = acb;
38840024Sgibbs		ccb->ccb_h.ccb_adw_ptr = adw;
38940024Sgibbs
39040024Sgibbs		acb->queue.cntl = 0;
39156979Sgibbs		acb->queue.target_cmd = 0;
39240024Sgibbs		acb->queue.target_id = ccb->ccb_h.target_id;
39340024Sgibbs		acb->queue.target_lun = ccb->ccb_h.target_lun;
39440024Sgibbs
39556979Sgibbs		acb->queue.mflag = 0;
39640024Sgibbs		acb->queue.sense_len =
39740024Sgibbs			MIN(csio->sense_len, sizeof(acb->sense_data));
39840024Sgibbs		acb->queue.cdb_len = csio->cdb_len;
39956979Sgibbs		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
40056979Sgibbs			switch (csio->tag_action) {
40156979Sgibbs			case MSG_SIMPLE_Q_TAG:
40257679Sgibbs				acb->queue.scsi_cntl = ADW_QSC_SIMPLE_Q_TAG;
40356979Sgibbs				break;
40456979Sgibbs			case MSG_HEAD_OF_Q_TAG:
40556979Sgibbs				acb->queue.scsi_cntl = ADW_QSC_HEAD_OF_Q_TAG;
40656979Sgibbs				break;
40756979Sgibbs			case MSG_ORDERED_Q_TAG:
40856979Sgibbs				acb->queue.scsi_cntl = ADW_QSC_ORDERED_Q_TAG;
40956979Sgibbs				break;
41057679Sgibbs			default:
41157679Sgibbs				acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
41257679Sgibbs				break;
41356979Sgibbs			}
41456979Sgibbs		} else
41556979Sgibbs			acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
41640024Sgibbs
41756979Sgibbs		if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
41856979Sgibbs			acb->queue.scsi_cntl |= ADW_QSC_NO_DISC;
41940024Sgibbs
42040024Sgibbs		acb->queue.done_status = 0;
42140024Sgibbs		acb->queue.scsi_status = 0;
42240024Sgibbs		acb->queue.host_status = 0;
42356979Sgibbs		acb->queue.sg_wk_ix = 0;
42440024Sgibbs		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
42540024Sgibbs			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
42640024Sgibbs				bcopy(csio->cdb_io.cdb_ptr,
42740024Sgibbs				      acb->queue.cdb, csio->cdb_len);
42840024Sgibbs			} else {
42940024Sgibbs				/* I guess I could map it in... */
43040024Sgibbs				ccb->ccb_h.status = CAM_REQ_INVALID;
43140024Sgibbs				adwfreeacb(adw, acb);
43240024Sgibbs				xpt_done(ccb);
43340024Sgibbs				return;
43440024Sgibbs			}
43540024Sgibbs		} else {
43640024Sgibbs			bcopy(csio->cdb_io.cdb_bytes,
43740024Sgibbs			      acb->queue.cdb, csio->cdb_len);
43840024Sgibbs		}
43940024Sgibbs
44040024Sgibbs		/*
44140024Sgibbs		 * If we have any data to send with this command,
44240024Sgibbs		 * map it into bus space.
44340024Sgibbs		 */
44440024Sgibbs		if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
44540024Sgibbs			if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
44640024Sgibbs				/*
44740024Sgibbs				 * We've been given a pointer
44840024Sgibbs				 * to a single buffer.
44940024Sgibbs				 */
45040024Sgibbs				if ((ccbh->flags & CAM_DATA_PHYS) == 0) {
45140024Sgibbs					int s;
45240024Sgibbs					int error;
45340024Sgibbs
45440024Sgibbs					s = splsoftvm();
45540024Sgibbs					error =
45640024Sgibbs					    bus_dmamap_load(adw->buffer_dmat,
45740024Sgibbs							    acb->dmamap,
45840024Sgibbs							    csio->data_ptr,
45940024Sgibbs							    csio->dxfer_len,
46040024Sgibbs							    adwexecuteacb,
46140024Sgibbs							    acb, /*flags*/0);
46240024Sgibbs					if (error == EINPROGRESS) {
46340024Sgibbs						/*
46440024Sgibbs						 * So as to maintain ordering,
46540024Sgibbs						 * freeze the controller queue
46640024Sgibbs						 * until our mapping is
46740024Sgibbs						 * returned.
46840024Sgibbs						 */
46940024Sgibbs						xpt_freeze_simq(sim, 1);
47040024Sgibbs						acb->state |= CAM_RELEASE_SIMQ;
47140024Sgibbs					}
47240024Sgibbs					splx(s);
47340024Sgibbs				} else {
47440024Sgibbs					struct bus_dma_segment seg;
47540024Sgibbs
47640024Sgibbs					/* Pointer to physical buffer */
47740024Sgibbs					seg.ds_addr =
47840024Sgibbs					    (bus_addr_t)csio->data_ptr;
47940024Sgibbs					seg.ds_len = csio->dxfer_len;
48040024Sgibbs					adwexecuteacb(acb, &seg, 1, 0);
48140024Sgibbs				}
48240024Sgibbs			} else {
48340024Sgibbs				struct bus_dma_segment *segs;
48440024Sgibbs
48540024Sgibbs				if ((ccbh->flags & CAM_DATA_PHYS) != 0)
48640024Sgibbs					panic("adw_action - Physical "
48740024Sgibbs					      "segment pointers "
48840024Sgibbs					      "unsupported");
48940024Sgibbs
49040024Sgibbs				if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
49140024Sgibbs					panic("adw_action - Virtual "
49240024Sgibbs					      "segment addresses "
49340024Sgibbs					      "unsupported");
49440024Sgibbs
49540024Sgibbs				/* Just use the segments provided */
49640024Sgibbs				segs = (struct bus_dma_segment *)csio->data_ptr;
49740024Sgibbs				adwexecuteacb(acb, segs, csio->sglist_cnt,
49840024Sgibbs					      (csio->sglist_cnt < ADW_SGSIZE)
49940024Sgibbs					      ? 0 : EFBIG);
50040024Sgibbs			}
50140024Sgibbs		} else {
50240024Sgibbs			adwexecuteacb(acb, NULL, 0, 0);
50340024Sgibbs		}
50440024Sgibbs		break;
50540024Sgibbs	}
50640024Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
50740024Sgibbs	{
50840024Sgibbs		adw_idle_cmd_status_t status;
50940024Sgibbs
51057679Sgibbs		status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
51157679Sgibbs					   ccb->ccb_h.target_id);
51240024Sgibbs		if (status == ADW_IDLE_CMD_SUCCESS) {
51340024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
51440024Sgibbs			if (bootverbose) {
51540024Sgibbs				xpt_print_path(ccb->ccb_h.path);
51640024Sgibbs				printf("BDR Delivered\n");
51740024Sgibbs			}
51840024Sgibbs		} else
51940024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
52040024Sgibbs		xpt_done(ccb);
52140024Sgibbs		break;
52240024Sgibbs	}
52340024Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
52440024Sgibbs		/* XXX Implement */
52540024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
52640024Sgibbs		xpt_done(ccb);
52740024Sgibbs		break;
52840024Sgibbs	case XPT_SET_TRAN_SETTINGS:
52940024Sgibbs	{
53040024Sgibbs		struct	  ccb_trans_settings *cts;
53140024Sgibbs		u_int	  target_mask;
53240024Sgibbs		int	  s;
53340024Sgibbs
53440024Sgibbs		cts = &ccb->cts;
53540024Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
53640024Sgibbs
53740024Sgibbs		s = splcam();
53840024Sgibbs		if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
53956979Sgibbs			u_int sdtrdone;
54056979Sgibbs
54156979Sgibbs			sdtrdone = adw_lram_read_16(adw, ADW_MC_SDTR_DONE);
54240024Sgibbs			if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
54340024Sgibbs				u_int discenb;
54440024Sgibbs
54540024Sgibbs				discenb =
54640024Sgibbs				    adw_lram_read_16(adw, ADW_MC_DISC_ENABLE);
54740024Sgibbs
54840024Sgibbs				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
54940024Sgibbs					discenb |= target_mask;
55040024Sgibbs				else
55140024Sgibbs					discenb &= ~target_mask;
55240024Sgibbs
55340024Sgibbs				adw_lram_write_16(adw, ADW_MC_DISC_ENABLE,
55440024Sgibbs						  discenb);
55540024Sgibbs			}
55640024Sgibbs
55740024Sgibbs			if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
55840024Sgibbs
55940024Sgibbs				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
56040024Sgibbs					adw->tagenb |= target_mask;
56140024Sgibbs				else
56240024Sgibbs					adw->tagenb &= ~target_mask;
56340024Sgibbs			}
56440024Sgibbs
56540024Sgibbs			if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
56640024Sgibbs				u_int wdtrenb_orig;
56740024Sgibbs				u_int wdtrenb;
56840024Sgibbs				u_int wdtrdone;
56940024Sgibbs
57040024Sgibbs				wdtrenb_orig =
57140024Sgibbs				    adw_lram_read_16(adw, ADW_MC_WDTR_ABLE);
57240024Sgibbs				wdtrenb = wdtrenb_orig;
57340024Sgibbs				wdtrdone = adw_lram_read_16(adw,
57440024Sgibbs							    ADW_MC_WDTR_DONE);
57540024Sgibbs				switch (cts->bus_width) {
57640024Sgibbs				case MSG_EXT_WDTR_BUS_32_BIT:
57740024Sgibbs				case MSG_EXT_WDTR_BUS_16_BIT:
57840024Sgibbs					wdtrenb |= target_mask;
57940024Sgibbs					break;
58040024Sgibbs				case MSG_EXT_WDTR_BUS_8_BIT:
58140024Sgibbs				default:
58240024Sgibbs					wdtrenb &= ~target_mask;
58340024Sgibbs					break;
58440024Sgibbs				}
58540024Sgibbs				if (wdtrenb != wdtrenb_orig) {
58640024Sgibbs					adw_lram_write_16(adw,
58740024Sgibbs							  ADW_MC_WDTR_ABLE,
58840024Sgibbs							  wdtrenb);
58940024Sgibbs					wdtrdone &= ~target_mask;
59040024Sgibbs					adw_lram_write_16(adw,
59140024Sgibbs							  ADW_MC_WDTR_DONE,
59240024Sgibbs							  wdtrdone);
59356979Sgibbs					/* Wide negotiation forces async */
59456979Sgibbs					sdtrdone &= ~target_mask;
59556979Sgibbs					adw_lram_write_16(adw,
59656979Sgibbs							  ADW_MC_SDTR_DONE,
59756979Sgibbs							  sdtrdone);
59840024Sgibbs				}
59940024Sgibbs			}
60040024Sgibbs
60146581Sken			if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
60246581Sken			 || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
60356979Sgibbs				u_int sdtr_orig;
60456979Sgibbs				u_int sdtr;
60556979Sgibbs				u_int sdtrable_orig;
60656979Sgibbs				u_int sdtrable;
60740024Sgibbs
60856979Sgibbs				sdtr = adw_get_chip_sdtr(adw,
60956979Sgibbs							 ccb->ccb_h.target_id);
61056979Sgibbs				sdtr_orig = sdtr;
61156979Sgibbs				sdtrable = adw_lram_read_16(adw,
61256979Sgibbs							    ADW_MC_SDTR_ABLE);
61356979Sgibbs				sdtrable_orig = sdtrable;
61440024Sgibbs
61546581Sken				if ((cts->valid
61646581Sken				   & CCB_TRANS_SYNC_RATE_VALID) != 0) {
61746581Sken
61856979Sgibbs					sdtr =
61956979Sgibbs					    adw_find_sdtr(adw,
62056979Sgibbs							  cts->sync_period);
62140024Sgibbs				}
62240024Sgibbs
62340024Sgibbs				if ((cts->valid
62440024Sgibbs				   & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
62540024Sgibbs					if (cts->sync_offset == 0)
62656979Sgibbs						sdtr = ADW_MC_SDTR_ASYNC;
62740024Sgibbs				}
62840024Sgibbs
62956979Sgibbs				if (sdtr == ADW_MC_SDTR_ASYNC)
63056979Sgibbs					sdtrable &= ~target_mask;
63156979Sgibbs				else
63256979Sgibbs					sdtrable |= target_mask;
63356979Sgibbs				if (sdtr != sdtr_orig
63456979Sgibbs				 || sdtrable != sdtrable_orig) {
63556979Sgibbs					adw_set_chip_sdtr(adw,
63656979Sgibbs							  ccb->ccb_h.target_id,
63756979Sgibbs							  sdtr);
63856979Sgibbs					sdtrdone &= ~target_mask;
63940024Sgibbs					adw_lram_write_16(adw, ADW_MC_SDTR_ABLE,
64056979Sgibbs							  sdtrable);
64140024Sgibbs					adw_lram_write_16(adw, ADW_MC_SDTR_DONE,
64240024Sgibbs							  sdtrdone);
64356979Sgibbs
64440024Sgibbs				}
64540024Sgibbs			}
64640024Sgibbs		}
64740024Sgibbs		splx(s);
64840024Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
64940024Sgibbs		xpt_done(ccb);
65040024Sgibbs		break;
65140024Sgibbs	}
65240024Sgibbs	case XPT_GET_TRAN_SETTINGS:
65340024Sgibbs	/* Get default/user set transfer settings for the target */
65440024Sgibbs	{
65540024Sgibbs		struct	ccb_trans_settings *cts;
65640024Sgibbs		u_int	target_mask;
65740024Sgibbs
65840024Sgibbs		cts = &ccb->cts;
65940024Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
66040024Sgibbs		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
66156979Sgibbs			u_int mc_sdtr;
66256979Sgibbs
66340024Sgibbs			cts->flags = 0;
66440024Sgibbs			if ((adw->user_discenb & target_mask) != 0)
66540024Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
66640024Sgibbs
66740024Sgibbs			if ((adw->user_tagenb & target_mask) != 0)
66840024Sgibbs				cts->flags |= CCB_TRANS_TAG_ENB;
66940024Sgibbs
67040024Sgibbs			if ((adw->user_wdtr & target_mask) != 0)
67140024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
67240024Sgibbs			else
67340024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
67440024Sgibbs
67556979Sgibbs			mc_sdtr = adw_get_user_sdtr(adw, ccb->ccb_h.target_id);
67656979Sgibbs			cts->sync_period = adw_find_period(adw, mc_sdtr);
67756979Sgibbs			if (cts->sync_period != 0)
67840024Sgibbs				cts->sync_offset = 15; /* XXX ??? */
67956979Sgibbs			else
68056979Sgibbs				cts->sync_offset = 0;
68140024Sgibbs
68240024Sgibbs			cts->valid = CCB_TRANS_SYNC_RATE_VALID
68340024Sgibbs				   | CCB_TRANS_SYNC_OFFSET_VALID
68440024Sgibbs				   | CCB_TRANS_BUS_WIDTH_VALID
68540024Sgibbs				   | CCB_TRANS_DISC_VALID
68640024Sgibbs				   | CCB_TRANS_TQ_VALID;
68740024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
68840024Sgibbs		} else {
68940024Sgibbs			u_int targ_tinfo;
69040024Sgibbs
69140024Sgibbs			cts->flags = 0;
69240024Sgibbs			if ((adw_lram_read_16(adw, ADW_MC_DISC_ENABLE)
69340024Sgibbs			  & target_mask) != 0)
69440024Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
69540024Sgibbs
69640024Sgibbs			if ((adw->tagenb & target_mask) != 0)
69740024Sgibbs				cts->flags |= CCB_TRANS_TAG_ENB;
69840024Sgibbs
69940024Sgibbs			targ_tinfo =
70040024Sgibbs			    adw_lram_read_16(adw,
70140024Sgibbs					     ADW_MC_DEVICE_HSHK_CFG_TABLE
70240024Sgibbs					     + (2 * ccb->ccb_h.target_id));
70340024Sgibbs
70440024Sgibbs			if ((targ_tinfo & ADW_HSHK_CFG_WIDE_XFR) != 0)
70540024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
70640024Sgibbs			else
70740024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
70840024Sgibbs
70940024Sgibbs			cts->sync_period =
71056979Sgibbs			    adw_hshk_cfg_period_factor(targ_tinfo);
71140024Sgibbs
71240024Sgibbs			cts->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET;
71340024Sgibbs			if (cts->sync_period == 0)
71440024Sgibbs				cts->sync_offset = 0;
71540024Sgibbs
71640024Sgibbs			if (cts->sync_offset == 0)
71740024Sgibbs				cts->sync_period = 0;
71840024Sgibbs		}
71940024Sgibbs		cts->valid = CCB_TRANS_SYNC_RATE_VALID
72040024Sgibbs			   | CCB_TRANS_SYNC_OFFSET_VALID
72140024Sgibbs			   | CCB_TRANS_BUS_WIDTH_VALID
72240024Sgibbs			   | CCB_TRANS_DISC_VALID
72340024Sgibbs			   | CCB_TRANS_TQ_VALID;
72440024Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
72540024Sgibbs		xpt_done(ccb);
72640024Sgibbs		break;
72740024Sgibbs	}
72840024Sgibbs	case XPT_CALC_GEOMETRY:
72940024Sgibbs	{
73040024Sgibbs		/*
73140024Sgibbs		 * XXX Use Adaptec translation until I find out how to
73240024Sgibbs		 *     get this information from the card.
73340024Sgibbs		 */
734116351Snjl		cam_calc_geometry(&ccb->ccg, /*extended*/1);
73540024Sgibbs		xpt_done(ccb);
73640024Sgibbs		break;
73740024Sgibbs	}
73840024Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
73940024Sgibbs	{
74057679Sgibbs		int failure;
74140024Sgibbs
74257679Sgibbs		failure = adw_reset_bus(adw);
74357679Sgibbs		if (failure != 0) {
74440024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
74557679Sgibbs		} else {
74657679Sgibbs			if (bootverbose) {
74757679Sgibbs				xpt_print_path(adw->path);
74857679Sgibbs				printf("Bus Reset Delivered\n");
74957679Sgibbs			}
75057679Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
75156979Sgibbs		}
75240024Sgibbs		xpt_done(ccb);
75340024Sgibbs		break;
75440024Sgibbs	}
75540024Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
75640024Sgibbs		/* XXX Implement */
75740024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
75840024Sgibbs		xpt_done(ccb);
75940024Sgibbs		break;
76040024Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
76140024Sgibbs	{
76240024Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
76340024Sgibbs
76440024Sgibbs		cpi->version_num = 1;
76540024Sgibbs		cpi->hba_inquiry = PI_WIDE_16|PI_SDTR_ABLE|PI_TAG_ABLE;
76640024Sgibbs		cpi->target_sprt = 0;
76740024Sgibbs		cpi->hba_misc = 0;
76840024Sgibbs		cpi->hba_eng_cnt = 0;
76940024Sgibbs		cpi->max_target = ADW_MAX_TID;
77040024Sgibbs		cpi->max_lun = ADW_MAX_LUN;
77140024Sgibbs		cpi->initiator_id = adw->initiator_id;
77240024Sgibbs		cpi->bus_id = cam_sim_bus(sim);
77346581Sken		cpi->base_transfer_speed = 3300;
77440024Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
77540024Sgibbs		strncpy(cpi->hba_vid, "AdvanSys", HBA_IDLEN);
77640024Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
77740024Sgibbs		cpi->unit_number = cam_sim_unit(sim);
77840024Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
77940024Sgibbs		xpt_done(ccb);
78040024Sgibbs		break;
78140024Sgibbs	}
78240024Sgibbs	default:
78340024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
78440024Sgibbs		xpt_done(ccb);
78540024Sgibbs		break;
78640024Sgibbs	}
78740024Sgibbs}
78840024Sgibbs
78940024Sgibbsstatic void
79040024Sgibbsadw_poll(struct cam_sim *sim)
79140024Sgibbs{
79240024Sgibbs	adw_intr(cam_sim_softc(sim));
79340024Sgibbs}
79440024Sgibbs
79540024Sgibbsstatic void
79640024Sgibbsadw_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
79740024Sgibbs{
79840024Sgibbs}
79940024Sgibbs
80040024Sgibbsstruct adw_softc *
80156979Sgibbsadw_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id)
80240024Sgibbs{
80340024Sgibbs	struct	 adw_softc *adw;
80440024Sgibbs	int	 i;
80540024Sgibbs
80640024Sgibbs	/*
80740024Sgibbs	 * Allocate a storage area for us
80840024Sgibbs	 */
80967888Sdwmalone	adw = malloc(sizeof(struct adw_softc), M_DEVBUF, M_NOWAIT | M_ZERO);
81040024Sgibbs	if (adw == NULL) {
81156979Sgibbs		printf("adw%d: cannot malloc!\n", device_get_unit(dev));
81240024Sgibbs		return NULL;
81340024Sgibbs	}
81440024Sgibbs	LIST_INIT(&adw->pending_ccbs);
81540024Sgibbs	SLIST_INIT(&adw->sg_maps);
81656979Sgibbs	adw->device = dev;
81756979Sgibbs	adw->unit = device_get_unit(dev);
81856979Sgibbs	adw->regs_res_type = regs_type;
81956979Sgibbs	adw->regs_res_id = regs_id;
82056979Sgibbs	adw->regs = regs;
82156979Sgibbs	adw->tag = rman_get_bustag(regs);
82256979Sgibbs	adw->bsh = rman_get_bushandle(regs);
82340024Sgibbs	i = adw->unit / 10;
82440024Sgibbs	adw->name = malloc(sizeof("adw") + i + 1, M_DEVBUF, M_NOWAIT);
82540024Sgibbs	if (adw->name == NULL) {
82656979Sgibbs		printf("adw%d: cannot malloc name!\n", adw->unit);
82740024Sgibbs		free(adw, M_DEVBUF);
82840024Sgibbs		return NULL;
82940024Sgibbs	}
83040024Sgibbs	sprintf(adw->name, "adw%d", adw->unit);
83140024Sgibbs	return(adw);
83240024Sgibbs}
83340024Sgibbs
83440024Sgibbsvoid
83540024Sgibbsadw_free(struct adw_softc *adw)
83640024Sgibbs{
83740024Sgibbs	switch (adw->init_level) {
83856979Sgibbs	case 9:
83940024Sgibbs	{
84040024Sgibbs		struct sg_map_node *sg_map;
84140024Sgibbs
84240024Sgibbs		while ((sg_map = SLIST_FIRST(&adw->sg_maps)) != NULL) {
84340024Sgibbs			SLIST_REMOVE_HEAD(&adw->sg_maps, links);
84440024Sgibbs			bus_dmamap_unload(adw->sg_dmat,
84540024Sgibbs					  sg_map->sg_dmamap);
84640024Sgibbs			bus_dmamem_free(adw->sg_dmat, sg_map->sg_vaddr,
84740024Sgibbs					sg_map->sg_dmamap);
84840024Sgibbs			free(sg_map, M_DEVBUF);
84940024Sgibbs		}
85040024Sgibbs		bus_dma_tag_destroy(adw->sg_dmat);
85140024Sgibbs	}
85256979Sgibbs	case 8:
85340024Sgibbs		bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap);
85456979Sgibbs	case 7:
85540024Sgibbs		bus_dmamem_free(adw->acb_dmat, adw->acbs,
85640024Sgibbs				adw->acb_dmamap);
85740024Sgibbs		bus_dmamap_destroy(adw->acb_dmat, adw->acb_dmamap);
85856979Sgibbs	case 6:
85956979Sgibbs		bus_dma_tag_destroy(adw->acb_dmat);
86056979Sgibbs	case 5:
86156979Sgibbs		bus_dmamap_unload(adw->carrier_dmat, adw->carrier_dmamap);
86256979Sgibbs	case 4:
86356979Sgibbs		bus_dmamem_free(adw->carrier_dmat, adw->carriers,
86456979Sgibbs				adw->carrier_dmamap);
86556979Sgibbs		bus_dmamap_destroy(adw->carrier_dmat, adw->carrier_dmamap);
86640024Sgibbs	case 3:
86756979Sgibbs		bus_dma_tag_destroy(adw->carrier_dmat);
86840024Sgibbs	case 2:
86940024Sgibbs		bus_dma_tag_destroy(adw->buffer_dmat);
87040024Sgibbs	case 1:
87140024Sgibbs		bus_dma_tag_destroy(adw->parent_dmat);
87240024Sgibbs	case 0:
87340024Sgibbs		break;
87440024Sgibbs	}
875138502Srsm
876138502Srsm	if (adw->regs != NULL)
877138502Srsm		bus_release_resource(adw->device,
878138502Srsm				     adw->regs_res_type,
879138502Srsm				     adw->regs_res_id,
880138502Srsm				     adw->regs);
881138502Srsm
882138502Srsm	if (adw->irq != NULL)
883138502Srsm		bus_release_resource(adw->device,
884138502Srsm				     adw->irq_res_type,
885138502Srsm				     0, adw->irq);
886138502Srsm
887138502Srsm	if (adw->sim != NULL) {
888138502Srsm		if (adw->path != NULL) {
889138502Srsm			xpt_async(AC_LOST_DEVICE, adw->path, NULL);
890138502Srsm			xpt_free_path(adw->path);
891138502Srsm		}
892138502Srsm		xpt_bus_deregister(cam_sim_path(adw->sim));
893138502Srsm		cam_sim_free(adw->sim, /*free_devq*/TRUE);
894138502Srsm	}
89540024Sgibbs	free(adw->name, M_DEVBUF);
89640024Sgibbs	free(adw, M_DEVBUF);
89740024Sgibbs}
89840024Sgibbs
89940024Sgibbsint
90040024Sgibbsadw_init(struct adw_softc *adw)
90140024Sgibbs{
90240024Sgibbs	struct	  adw_eeprom eep_config;
90356979Sgibbs	u_int	  tid;
90456979Sgibbs	u_int	  i;
90540024Sgibbs	u_int16_t checksum;
90640024Sgibbs	u_int16_t scsicfg1;
90740024Sgibbs
90840024Sgibbs	checksum = adw_eeprom_read(adw, &eep_config);
90940024Sgibbs	bcopy(eep_config.serial_number, adw->serial_number,
91040024Sgibbs	      sizeof(adw->serial_number));
91140024Sgibbs	if (checksum != eep_config.checksum) {
91240024Sgibbs		u_int16_t serial_number[3];
91340024Sgibbs
91456979Sgibbs		adw->flags |= ADW_EEPROM_FAILED;
91540024Sgibbs		printf("%s: EEPROM checksum failed.  Restoring Defaults\n",
91640024Sgibbs		       adw_name(adw));
91740024Sgibbs
91840024Sgibbs	        /*
91940024Sgibbs		 * Restore the default EEPROM settings.
92040024Sgibbs		 * Assume the 6 byte board serial number that was read
92140024Sgibbs		 * from EEPROM is correct even if the EEPROM checksum
92240024Sgibbs		 * failed.
92340024Sgibbs		 */
92456979Sgibbs		bcopy(adw->default_eeprom, &eep_config, sizeof(eep_config));
92540024Sgibbs		bcopy(adw->serial_number, eep_config.serial_number,
92640024Sgibbs		      sizeof(serial_number));
92740024Sgibbs		adw_eeprom_write(adw, &eep_config);
92840024Sgibbs	}
92940024Sgibbs
93040024Sgibbs	/* Pull eeprom information into our softc. */
93140024Sgibbs	adw->bios_ctrl = eep_config.bios_ctrl;
93240024Sgibbs	adw->user_wdtr = eep_config.wdtr_able;
93356979Sgibbs	for (tid = 0; tid < ADW_MAX_TID; tid++) {
93456979Sgibbs		u_int	  mc_sdtr;
93556979Sgibbs		u_int16_t tid_mask;
93656979Sgibbs
93756979Sgibbs		tid_mask = 0x1 << tid;
93856979Sgibbs		if ((adw->features & ADW_ULTRA) != 0) {
93956979Sgibbs			/*
94056979Sgibbs			 * Ultra chips store sdtr and ultraenb
94156979Sgibbs			 * bits in their seeprom, so we must
94256979Sgibbs			 * construct valid mc_sdtr entries for
94356979Sgibbs			 * indirectly.
94456979Sgibbs			 */
94556979Sgibbs			if (eep_config.sync1.sync_enable & tid_mask) {
94656979Sgibbs				if (eep_config.sync2.ultra_enable & tid_mask)
94756979Sgibbs					mc_sdtr = ADW_MC_SDTR_20;
94856979Sgibbs				else
94956979Sgibbs					mc_sdtr = ADW_MC_SDTR_10;
95056979Sgibbs			} else
95156979Sgibbs				mc_sdtr = ADW_MC_SDTR_ASYNC;
95256979Sgibbs		} else {
95356979Sgibbs			switch (ADW_TARGET_GROUP(tid)) {
95456979Sgibbs			case 3:
95556979Sgibbs				mc_sdtr = eep_config.sync4.sdtr4;
95656979Sgibbs				break;
95756979Sgibbs			case 2:
95856979Sgibbs				mc_sdtr = eep_config.sync3.sdtr3;
95956979Sgibbs				break;
96056979Sgibbs			case 1:
96156979Sgibbs				mc_sdtr = eep_config.sync2.sdtr2;
96256979Sgibbs				break;
96356979Sgibbs			default: /* Shut up compiler */
96456979Sgibbs			case 0:
96556979Sgibbs				mc_sdtr = eep_config.sync1.sdtr1;
96656979Sgibbs				break;
96756979Sgibbs			}
96856979Sgibbs			mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid);
96956979Sgibbs			mc_sdtr &= 0xFF;
97056979Sgibbs		}
97156979Sgibbs		adw_set_user_sdtr(adw, tid, mc_sdtr);
97256979Sgibbs	}
97340024Sgibbs	adw->user_tagenb = eep_config.tagqng_able;
97440024Sgibbs	adw->user_discenb = eep_config.disc_enable;
97540024Sgibbs	adw->max_acbs = eep_config.max_host_qng;
97640024Sgibbs	adw->initiator_id = (eep_config.adapter_scsi_id & ADW_MAX_TID);
97740024Sgibbs
97840024Sgibbs	/*
97940024Sgibbs	 * Sanity check the number of host openings.
98040024Sgibbs	 */
98140024Sgibbs	if (adw->max_acbs > ADW_DEF_MAX_HOST_QNG)
98240024Sgibbs		adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
98340024Sgibbs	else if (adw->max_acbs < ADW_DEF_MIN_HOST_QNG) {
98440024Sgibbs        	/* If the value is zero, assume it is uninitialized. */
98540024Sgibbs		if (adw->max_acbs == 0)
98640024Sgibbs			adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
98740024Sgibbs		else
98840024Sgibbs			adw->max_acbs = ADW_DEF_MIN_HOST_QNG;
98940024Sgibbs	}
99040024Sgibbs
99140024Sgibbs	scsicfg1 = 0;
99256979Sgibbs	if ((adw->features & ADW_ULTRA2) != 0) {
99356979Sgibbs		switch (eep_config.termination_lvd) {
99456979Sgibbs		default:
99556979Sgibbs			printf("%s: Invalid EEPROM LVD Termination Settings.\n",
99656979Sgibbs			       adw_name(adw));
99756979Sgibbs			printf("%s: Reverting to Automatic LVD Termination\n",
99856979Sgibbs			       adw_name(adw));
99956979Sgibbs			/* FALLTHROUGH */
100056979Sgibbs		case ADW_EEPROM_TERM_AUTO:
100156979Sgibbs			break;
100256979Sgibbs		case ADW_EEPROM_TERM_BOTH_ON:
100356979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_LO;
100456979Sgibbs			/* FALLTHROUGH */
100556979Sgibbs		case ADW_EEPROM_TERM_HIGH_ON:
100656979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_HI;
100756979Sgibbs			/* FALLTHROUGH */
100856979Sgibbs		case ADW_EEPROM_TERM_OFF:
100956979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_DIS_TERM_DRV;
101056979Sgibbs			break;
101156979Sgibbs		}
101256979Sgibbs	}
101356979Sgibbs
101456979Sgibbs	switch (eep_config.termination_se) {
101540024Sgibbs	default:
101656979Sgibbs		printf("%s: Invalid SE EEPROM Termination Settings.\n",
101740024Sgibbs		       adw_name(adw));
101856979Sgibbs		printf("%s: Reverting to Automatic SE Termination\n",
101940024Sgibbs		       adw_name(adw));
102040024Sgibbs		/* FALLTHROUGH */
102140024Sgibbs	case ADW_EEPROM_TERM_AUTO:
102240024Sgibbs		break;
102340024Sgibbs	case ADW_EEPROM_TERM_BOTH_ON:
102440024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L;
102540024Sgibbs		/* FALLTHROUGH */
102640024Sgibbs	case ADW_EEPROM_TERM_HIGH_ON:
102740024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H;
102840024Sgibbs		/* FALLTHROUGH */
102940024Sgibbs	case ADW_EEPROM_TERM_OFF:
103040024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL;
103140024Sgibbs		break;
103240024Sgibbs	}
103340024Sgibbs	printf("%s: SCSI ID %d, ", adw_name(adw), adw->initiator_id);
103440024Sgibbs
103540024Sgibbs	/* DMA tag for mapping buffers into device visible space. */
1036112782Smdodd	if (bus_dma_tag_create(
1037112782Smdodd			/* parent	*/ adw->parent_dmat,
1038112782Smdodd			/* alignment	*/ 1,
1039112782Smdodd			/* boundary	*/ 0,
1040112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
1041112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1042112782Smdodd			/* filter	*/ NULL,
1043112782Smdodd			/* filterarg	*/ NULL,
1044112782Smdodd			/* maxsize	*/ MAXBSIZE,
1045112782Smdodd			/* nsegments	*/ ADW_SGSIZE,
1046112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1047112782Smdodd			/* flags	*/ BUS_DMA_ALLOCNOW,
1048117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1049117126Sscottl			/* lockarg	*/ &Giant,
1050112782Smdodd			&adw->buffer_dmat) != 0) {
105156979Sgibbs		return (ENOMEM);
105240024Sgibbs	}
105340024Sgibbs
105440024Sgibbs	adw->init_level++;
105540024Sgibbs
105656979Sgibbs	/* DMA tag for our ccb carrier structures */
1057112782Smdodd	if (bus_dma_tag_create(
1058112782Smdodd			/* parent	*/ adw->parent_dmat,
1059112782Smdodd			/* alignment	*/ 0x10,
1060112782Smdodd			/* boundary	*/ 0,
1061112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
1062112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1063112782Smdodd			/* filter	*/ NULL,
1064112782Smdodd			/* filterarg	*/ NULL,
1065112782Smdodd			/* maxsize	*/ (adw->max_acbs +
1066112782Smdodd					    ADW_NUM_CARRIER_QUEUES + 1) *
1067112782Smdodd					    sizeof(struct adw_carrier),
1068112782Smdodd			/* nsegments	*/ 1,
1069112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1070112782Smdodd			/* flags	*/ 0,
1071117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1072117126Sscottl			/* lockarg	*/ &Giant,
1073112782Smdodd			&adw->carrier_dmat) != 0) {
107456979Sgibbs		return (ENOMEM);
107556979Sgibbs        }
107656979Sgibbs
107756979Sgibbs	adw->init_level++;
107856979Sgibbs
107956979Sgibbs	/* Allocation for our ccb carrier structures */
108056979Sgibbs	if (bus_dmamem_alloc(adw->carrier_dmat, (void **)&adw->carriers,
108156979Sgibbs			     BUS_DMA_NOWAIT, &adw->carrier_dmamap) != 0) {
108256979Sgibbs		return (ENOMEM);
108356979Sgibbs	}
108456979Sgibbs
108556979Sgibbs	adw->init_level++;
108656979Sgibbs
108756979Sgibbs	/* And permanently map them */
108856979Sgibbs	bus_dmamap_load(adw->carrier_dmat, adw->carrier_dmamap,
108956979Sgibbs			adw->carriers,
109056979Sgibbs			(adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
109156979Sgibbs			 * sizeof(struct adw_carrier),
109256979Sgibbs			adwmapmem, &adw->carrier_busbase, /*flags*/0);
109356979Sgibbs
109456979Sgibbs	/* Clear them out. */
109556979Sgibbs	bzero(adw->carriers, (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
109656979Sgibbs			     * sizeof(struct adw_carrier));
109756979Sgibbs
109856979Sgibbs	/* Setup our free carrier list */
109956979Sgibbs	adw->free_carriers = adw->carriers;
110056979Sgibbs	for (i = 0; i < adw->max_acbs + ADW_NUM_CARRIER_QUEUES; i++) {
110156979Sgibbs		adw->carriers[i].carr_offset =
110256979Sgibbs			carriervtobo(adw, &adw->carriers[i]);
110356979Sgibbs		adw->carriers[i].carr_ba =
110456979Sgibbs			carriervtob(adw, &adw->carriers[i]);
110556979Sgibbs		adw->carriers[i].areq_ba = 0;
110656979Sgibbs		adw->carriers[i].next_ba =
110756979Sgibbs			carriervtobo(adw, &adw->carriers[i+1]);
110856979Sgibbs	}
110956979Sgibbs	/* Terminal carrier.  Never leaves the freelist */
111056979Sgibbs	adw->carriers[i].carr_offset =
111156979Sgibbs		carriervtobo(adw, &adw->carriers[i]);
111256979Sgibbs	adw->carriers[i].carr_ba =
111356979Sgibbs		carriervtob(adw, &adw->carriers[i]);
111456979Sgibbs	adw->carriers[i].areq_ba = 0;
111556979Sgibbs	adw->carriers[i].next_ba = ~0;
111656979Sgibbs
111756979Sgibbs	adw->init_level++;
111856979Sgibbs
111956979Sgibbs	/* DMA tag for our acb structures */
1120112782Smdodd	if (bus_dma_tag_create(
1121112782Smdodd			/* parent	*/ adw->parent_dmat,
1122112782Smdodd			/* alignment	*/ 1,
1123112782Smdodd			/* boundary	*/ 0,
1124112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1125112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1126112782Smdodd			/* filter	*/ NULL,
1127112782Smdodd			/* filterarg	*/ NULL,
1128112782Smdodd			/* maxsize	*/ adw->max_acbs * sizeof(struct acb),
1129112782Smdodd			/* nsegments	*/ 1,
1130112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1131112782Smdodd			/* flags	*/ 0,
1132117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1133117126Sscottl			/* lockarg	*/ &Giant,
1134112782Smdodd			&adw->acb_dmat) != 0) {
113556979Sgibbs		return (ENOMEM);
113640024Sgibbs        }
113740024Sgibbs
113840024Sgibbs	adw->init_level++;
113940024Sgibbs
114040024Sgibbs	/* Allocation for our ccbs */
114140024Sgibbs	if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs,
114256979Sgibbs			     BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0)
114356979Sgibbs		return (ENOMEM);
114440024Sgibbs
114540024Sgibbs	adw->init_level++;
114640024Sgibbs
114740024Sgibbs	/* And permanently map them */
114840024Sgibbs	bus_dmamap_load(adw->acb_dmat, adw->acb_dmamap,
114940024Sgibbs			adw->acbs,
115040024Sgibbs			adw->max_acbs * sizeof(struct acb),
115140024Sgibbs			adwmapmem, &adw->acb_busbase, /*flags*/0);
115240024Sgibbs
115340024Sgibbs	/* Clear them out. */
115440024Sgibbs	bzero(adw->acbs, adw->max_acbs * sizeof(struct acb));
115540024Sgibbs
115640024Sgibbs	/* DMA tag for our S/G structures.  We allocate in page sized chunks */
1157112782Smdodd	if (bus_dma_tag_create(
1158112782Smdodd			/* parent	*/ adw->parent_dmat,
1159112782Smdodd			/* alignment	*/ 1,
1160112782Smdodd			/* boundary	*/ 0,
1161112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1162112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1163112782Smdodd			/* filter	*/ NULL,
1164112782Smdodd			/* filterarg	*/ NULL,
1165112782Smdodd			/* maxsize	*/ PAGE_SIZE,
1166112782Smdodd			/* nsegments	*/ 1,
1167112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1168112782Smdodd			/* flags	*/ 0,
1169117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1170117126Sscottl			/* lockarg	*/ &Giant,
1171112782Smdodd			&adw->sg_dmat) != 0) {
117256979Sgibbs		return (ENOMEM);
117340024Sgibbs        }
117440024Sgibbs
117540024Sgibbs	adw->init_level++;
117640024Sgibbs
117740024Sgibbs	/* Allocate our first batch of ccbs */
117840024Sgibbs	if (adwallocacbs(adw) == 0)
117956979Sgibbs		return (ENOMEM);
118040024Sgibbs
118156979Sgibbs	if (adw_init_chip(adw, scsicfg1) != 0)
118256979Sgibbs		return (ENXIO);
118356979Sgibbs
118456979Sgibbs	printf("Queue Depth %d\n", adw->max_acbs);
118556979Sgibbs
118640024Sgibbs	return (0);
118740024Sgibbs}
118840024Sgibbs
118940024Sgibbs/*
119040024Sgibbs * Attach all the sub-devices we can find
119140024Sgibbs */
119240024Sgibbsint
119340024Sgibbsadw_attach(struct adw_softc *adw)
119440024Sgibbs{
119540024Sgibbs	struct ccb_setasync csa;
119640024Sgibbs	struct cam_devq *devq;
119756979Sgibbs	int s;
119856979Sgibbs	int error;
119940024Sgibbs
120056979Sgibbs	error = 0;
120156979Sgibbs	s = splcam();
120256979Sgibbs	/* Hook up our interrupt handler */
120373280Smarkm	if ((error = bus_setup_intr(adw->device, adw->irq,
120473280Smarkm				    INTR_TYPE_CAM | INTR_ENTROPY, adw_intr,
120573280Smarkm				    adw, &adw->ih)) != 0) {
120656979Sgibbs		device_printf(adw->device, "bus_setup_intr() failed: %d\n",
120756979Sgibbs			      error);
120856979Sgibbs		goto fail;
120956979Sgibbs	}
121056979Sgibbs
121140024Sgibbs	/* Start the Risc processor now that we are fully configured. */
121240024Sgibbs	adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN);
121340024Sgibbs
121440024Sgibbs	/*
121540024Sgibbs	 * Create the device queue for our SIM.
121640024Sgibbs	 */
121740024Sgibbs	devq = cam_simq_alloc(adw->max_acbs);
121840024Sgibbs	if (devq == NULL)
121956979Sgibbs		return (ENOMEM);
122040024Sgibbs
122140024Sgibbs	/*
122240024Sgibbs	 * Construct our SIM entry.
122340024Sgibbs	 */
122440024Sgibbs	adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw, adw->unit,
122540024Sgibbs				 1, adw->max_acbs, devq);
122656979Sgibbs	if (adw->sim == NULL) {
122756979Sgibbs		error = ENOMEM;
122856979Sgibbs		goto fail;
122956979Sgibbs	}
123040024Sgibbs
123140024Sgibbs	/*
123240024Sgibbs	 * Register the bus.
123340024Sgibbs	 */
123440024Sgibbs	if (xpt_bus_register(adw->sim, 0) != CAM_SUCCESS) {
123540024Sgibbs		cam_sim_free(adw->sim, /*free devq*/TRUE);
123656979Sgibbs		error = ENOMEM;
123756979Sgibbs		goto fail;
123840024Sgibbs	}
123940024Sgibbs
124040024Sgibbs	if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim),
124140024Sgibbs			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
124240024Sgibbs	   == CAM_REQ_CMP) {
124340024Sgibbs		xpt_setup_ccb(&csa.ccb_h, adw->path, /*priority*/5);
124440024Sgibbs		csa.ccb_h.func_code = XPT_SASYNC_CB;
124540024Sgibbs		csa.event_enable = AC_LOST_DEVICE;
124640024Sgibbs		csa.callback = adw_async;
124740024Sgibbs		csa.callback_arg = adw;
124840024Sgibbs		xpt_action((union ccb *)&csa);
124940024Sgibbs	}
125040024Sgibbs
125156979Sgibbsfail:
125256979Sgibbs	splx(s);
125356979Sgibbs	return (error);
125440024Sgibbs}
125540024Sgibbs
125640024Sgibbsvoid
125740024Sgibbsadw_intr(void *arg)
125840024Sgibbs{
125940024Sgibbs	struct	adw_softc *adw;
126040024Sgibbs	u_int	int_stat;
126140024Sgibbs
126240024Sgibbs	adw = (struct adw_softc *)arg;
126340024Sgibbs	if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0)
126440024Sgibbs		return;
126540024Sgibbs
126640024Sgibbs	/* Reading the register clears the interrupt. */
126740024Sgibbs	int_stat = adw_inb(adw, ADW_INTR_STATUS_REG);
126840024Sgibbs
126940024Sgibbs	if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) {
127056979Sgibbs		u_int intrb_code;
127156979Sgibbs
127256979Sgibbs		/* Async Microcode Event */
127356979Sgibbs		intrb_code = adw_lram_read_8(adw, ADW_MC_INTRB_CODE);
127456979Sgibbs		switch (intrb_code) {
127556979Sgibbs		case ADW_ASYNC_CARRIER_READY_FAILURE:
127656979Sgibbs			/*
127756979Sgibbs			 * The RISC missed our update of
127856979Sgibbs			 * the commandq.
127956979Sgibbs			 */
128056979Sgibbs			if (LIST_FIRST(&adw->pending_ccbs) != NULL)
128156979Sgibbs				adw_tickle_risc(adw, ADW_TICKLE_A);
128240024Sgibbs			break;
128356979Sgibbs    		case ADW_ASYNC_SCSI_BUS_RESET_DET:
128456979Sgibbs			/*
128556979Sgibbs			 * The firmware detected a SCSI Bus reset.
128656979Sgibbs			 */
128756979Sgibbs			printf("Someone Reset the Bus\n");
128856979Sgibbs			adw_handle_bus_reset(adw, /*initiated*/FALSE);
128956979Sgibbs			break;
129056979Sgibbs		case ADW_ASYNC_RDMA_FAILURE:
129156979Sgibbs			/*
129256979Sgibbs			 * Handle RDMA failure by resetting the
129356979Sgibbs			 * SCSI Bus and chip.
129456979Sgibbs			 */
129556979Sgibbs#if XXX
129656979Sgibbs			AdvResetChipAndSB(adv_dvc_varp);
129756979Sgibbs#endif
129856979Sgibbs			break;
129956979Sgibbs
130056979Sgibbs		case ADW_ASYNC_HOST_SCSI_BUS_RESET:
130156979Sgibbs			/*
130256979Sgibbs			 * Host generated SCSI bus reset occurred.
130356979Sgibbs			 */
130440024Sgibbs			adw_handle_bus_reset(adw, /*initiated*/TRUE);
130556979Sgibbs        		break;
130656979Sgibbs    		default:
130756979Sgibbs			printf("adw_intr: unknown async code 0x%x\n",
130856979Sgibbs			       intrb_code);
130940024Sgibbs			break;
131040024Sgibbs		}
131140024Sgibbs	}
131240024Sgibbs
131340024Sgibbs	/*
131456979Sgibbs	 * Run down the RequestQ.
131540024Sgibbs	 */
131656979Sgibbs	while ((adw->responseq->next_ba & ADW_RQ_DONE) != 0) {
131756979Sgibbs		struct adw_carrier *free_carrier;
131856979Sgibbs		struct acb *acb;
131956979Sgibbs		union ccb *ccb;
132040024Sgibbs
132156979Sgibbs#if 0
132256979Sgibbs		printf("0x%x, 0x%x, 0x%x, 0x%x\n",
132356979Sgibbs		       adw->responseq->carr_offset,
132456979Sgibbs		       adw->responseq->carr_ba,
132556979Sgibbs		       adw->responseq->areq_ba,
132656979Sgibbs		       adw->responseq->next_ba);
132756979Sgibbs#endif
132856979Sgibbs		/*
132956979Sgibbs		 * The firmware copies the adw_scsi_req_q.acb_baddr
133056979Sgibbs		 * field into the areq_ba field of the carrier.
133156979Sgibbs		 */
133256979Sgibbs		acb = acbbotov(adw, adw->responseq->areq_ba);
133340024Sgibbs
133440024Sgibbs		/*
133556979Sgibbs		 * The least significant four bits of the next_ba
133656979Sgibbs		 * field are used as flags.  Mask them out and then
133756979Sgibbs		 * advance through the list.
133840024Sgibbs		 */
133956979Sgibbs		free_carrier = adw->responseq;
134056979Sgibbs		adw->responseq =
134156979Sgibbs		    carrierbotov(adw, free_carrier->next_ba & ADW_NEXT_BA_MASK);
134256979Sgibbs		free_carrier->next_ba = adw->free_carriers->carr_offset;
134356979Sgibbs		adw->free_carriers = free_carrier;
134440024Sgibbs
134540024Sgibbs		/* Process CCB */
134640024Sgibbs		ccb = acb->ccb;
134740024Sgibbs		untimeout(adwtimeout, acb, ccb->ccb_h.timeout_ch);
134840024Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
1349115343Sscottl			bus_dmasync_op_t op;
135040024Sgibbs
135140024Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
135240024Sgibbs				op = BUS_DMASYNC_POSTREAD;
135340024Sgibbs			else
135440024Sgibbs				op = BUS_DMASYNC_POSTWRITE;
135540024Sgibbs			bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
135640024Sgibbs			bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
135740024Sgibbs			ccb->csio.resid = acb->queue.data_cnt;
135840024Sgibbs		} else
135940024Sgibbs			ccb->csio.resid = 0;
136040024Sgibbs
136140024Sgibbs		/* Common Cases inline... */
136240024Sgibbs		if (acb->queue.host_status == QHSTA_NO_ERROR
136340024Sgibbs		 && (acb->queue.done_status == QD_NO_ERROR
136440024Sgibbs		  || acb->queue.done_status == QD_WITH_ERROR)) {
136540024Sgibbs			ccb->csio.scsi_status = acb->queue.scsi_status;
136640024Sgibbs			ccb->ccb_h.status = 0;
136740024Sgibbs			switch (ccb->csio.scsi_status) {
136840024Sgibbs			case SCSI_STATUS_OK:
136940024Sgibbs				ccb->ccb_h.status |= CAM_REQ_CMP;
137040024Sgibbs				break;
137140024Sgibbs			case SCSI_STATUS_CHECK_COND:
137240024Sgibbs			case SCSI_STATUS_CMD_TERMINATED:
137340024Sgibbs				bcopy(&acb->sense_data, &ccb->csio.sense_data,
137440024Sgibbs				      ccb->csio.sense_len);
137540024Sgibbs				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
137640024Sgibbs				ccb->csio.sense_resid = acb->queue.sense_len;
137740024Sgibbs				/* FALLTHROUGH */
137840024Sgibbs			default:
137940024Sgibbs				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR
138040024Sgibbs						  |  CAM_DEV_QFRZN;
138140024Sgibbs				xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
138240024Sgibbs				break;
138340024Sgibbs			}
138440024Sgibbs			adwfreeacb(adw, acb);
138540024Sgibbs			xpt_done(ccb);
138640024Sgibbs		} else {
138740024Sgibbs			adwprocesserror(adw, acb);
138840024Sgibbs		}
138940024Sgibbs	}
139040024Sgibbs}
139140024Sgibbs
139240024Sgibbsstatic void
139340024Sgibbsadwprocesserror(struct adw_softc *adw, struct acb *acb)
139440024Sgibbs{
139540024Sgibbs	union ccb *ccb;
139640024Sgibbs
139740024Sgibbs	ccb = acb->ccb;
139840024Sgibbs	if (acb->queue.done_status == QD_ABORTED_BY_HOST) {
139940024Sgibbs		ccb->ccb_h.status = CAM_REQ_ABORTED;
140040024Sgibbs	} else {
140140024Sgibbs
140240024Sgibbs		switch (acb->queue.host_status) {
140340024Sgibbs		case QHSTA_M_SEL_TIMEOUT:
140440024Sgibbs			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
140540024Sgibbs			break;
140640024Sgibbs		case QHSTA_M_SXFR_OFF_UFLW:
140740024Sgibbs		case QHSTA_M_SXFR_OFF_OFLW:
140840024Sgibbs		case QHSTA_M_DATA_OVER_RUN:
140940024Sgibbs			ccb->ccb_h.status = CAM_DATA_RUN_ERR;
141040024Sgibbs			break;
141140024Sgibbs		case QHSTA_M_SXFR_DESELECTED:
141240024Sgibbs		case QHSTA_M_UNEXPECTED_BUS_FREE:
141340024Sgibbs			ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
141440024Sgibbs			break;
141557679Sgibbs		case QHSTA_M_SCSI_BUS_RESET:
141657679Sgibbs		case QHSTA_M_SCSI_BUS_RESET_UNSOL:
141757679Sgibbs			ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
141857679Sgibbs			break;
141957679Sgibbs		case QHSTA_M_BUS_DEVICE_RESET:
142057679Sgibbs			ccb->ccb_h.status = CAM_BDR_SENT;
142157679Sgibbs			break;
142240024Sgibbs		case QHSTA_M_QUEUE_ABORTED:
142340024Sgibbs			/* BDR or Bus Reset */
142457679Sgibbs			printf("Saw Queue Aborted\n");
142540024Sgibbs			ccb->ccb_h.status = adw->last_reset;
142640024Sgibbs			break;
142740024Sgibbs		case QHSTA_M_SXFR_SDMA_ERR:
142840024Sgibbs		case QHSTA_M_SXFR_SXFR_PERR:
142940024Sgibbs		case QHSTA_M_RDMA_PERR:
143040024Sgibbs			ccb->ccb_h.status = CAM_UNCOR_PARITY;
143140024Sgibbs			break;
143240024Sgibbs		case QHSTA_M_WTM_TIMEOUT:
143340024Sgibbs		case QHSTA_M_SXFR_WD_TMO:
143456979Sgibbs		{
143540024Sgibbs			/* The SCSI bus hung in a phase */
143657679Sgibbs			xpt_print_path(adw->path);
143757679Sgibbs			printf("Watch Dog timer expired.  Reseting bus\n");
143857679Sgibbs			adw_reset_bus(adw);
143940024Sgibbs			break;
144056979Sgibbs		}
144140024Sgibbs		case QHSTA_M_SXFR_XFR_PH_ERR:
144240024Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
144340024Sgibbs			break;
144440024Sgibbs		case QHSTA_M_SXFR_UNKNOWN_ERROR:
144540024Sgibbs			break;
144640024Sgibbs		case QHSTA_M_BAD_CMPL_STATUS_IN:
144740024Sgibbs			/* No command complete after a status message */
144840024Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
144940024Sgibbs			break;
145040024Sgibbs		case QHSTA_M_AUTO_REQ_SENSE_FAIL:
145140024Sgibbs			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
145240024Sgibbs			break;
145340024Sgibbs		case QHSTA_M_INVALID_DEVICE:
145440024Sgibbs			ccb->ccb_h.status = CAM_PATH_INVALID;
145540024Sgibbs			break;
145640024Sgibbs		case QHSTA_M_NO_AUTO_REQ_SENSE:
145740024Sgibbs			/*
145840024Sgibbs			 * User didn't request sense, but we got a
145940024Sgibbs			 * check condition.
146040024Sgibbs			 */
146140024Sgibbs			ccb->csio.scsi_status = acb->queue.scsi_status;
146240024Sgibbs			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
146340024Sgibbs			break;
146440024Sgibbs		default:
146540024Sgibbs			panic("%s: Unhandled Host status error %x",
146640024Sgibbs			      adw_name(adw), acb->queue.host_status);
146740024Sgibbs			/* NOTREACHED */
146840024Sgibbs		}
146940024Sgibbs	}
147057679Sgibbs	if ((acb->state & ACB_RECOVERY_ACB) != 0) {
147157679Sgibbs		if (ccb->ccb_h.status == CAM_SCSI_BUS_RESET
147257679Sgibbs		 || ccb->ccb_h.status == CAM_BDR_SENT)
147357679Sgibbs		 	ccb->ccb_h.status = CAM_CMD_TIMEOUT;
147457679Sgibbs	}
147540024Sgibbs	if (ccb->ccb_h.status != CAM_REQ_CMP) {
147640024Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
147740024Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
147840024Sgibbs	}
147940024Sgibbs	adwfreeacb(adw, acb);
148040024Sgibbs	xpt_done(ccb);
148140024Sgibbs}
148240024Sgibbs
148340024Sgibbsstatic void
148440024Sgibbsadwtimeout(void *arg)
148540024Sgibbs{
148640024Sgibbs	struct acb	     *acb;
148740024Sgibbs	union  ccb	     *ccb;
148840024Sgibbs	struct adw_softc     *adw;
148940024Sgibbs	adw_idle_cmd_status_t status;
149057679Sgibbs	int		      target_id;
149140024Sgibbs	int		      s;
149240024Sgibbs
149340024Sgibbs	acb = (struct acb *)arg;
149440024Sgibbs	ccb = acb->ccb;
149540024Sgibbs	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
149640024Sgibbs	xpt_print_path(ccb->ccb_h.path);
149740024Sgibbs	printf("ACB %p - timed out\n", (void *)acb);
149840024Sgibbs
149940024Sgibbs	s = splcam();
150040024Sgibbs
150140024Sgibbs	if ((acb->state & ACB_ACTIVE) == 0) {
150240024Sgibbs		xpt_print_path(ccb->ccb_h.path);
150340024Sgibbs		printf("ACB %p - timed out CCB already completed\n",
150440024Sgibbs		       (void *)acb);
150540024Sgibbs		splx(s);
150640024Sgibbs		return;
150740024Sgibbs	}
150840024Sgibbs
150957679Sgibbs	acb->state |= ACB_RECOVERY_ACB;
151057679Sgibbs	target_id = ccb->ccb_h.target_id;
151157679Sgibbs
151240024Sgibbs	/* Attempt a BDR first */
151357679Sgibbs	status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
151457679Sgibbs				   ccb->ccb_h.target_id);
151540024Sgibbs	splx(s);
151640024Sgibbs	if (status == ADW_IDLE_CMD_SUCCESS) {
151740024Sgibbs		printf("%s: BDR Delivered.  No longer in timeout\n",
151840024Sgibbs		       adw_name(adw));
151957679Sgibbs		adw_handle_device_reset(adw, target_id);
152040024Sgibbs	} else {
152157679Sgibbs		adw_reset_bus(adw);
152257679Sgibbs		xpt_print_path(adw->path);
152357679Sgibbs		printf("Bus Reset Delivered.  No longer in timeout\n");
152440024Sgibbs	}
152540024Sgibbs}
152640024Sgibbs
152740024Sgibbsstatic void
152840024Sgibbsadw_handle_device_reset(struct adw_softc *adw, u_int target)
152940024Sgibbs{
153040024Sgibbs	struct cam_path *path;
153140024Sgibbs	cam_status error;
153240024Sgibbs
153340024Sgibbs	error = xpt_create_path(&path, /*periph*/NULL, cam_sim_path(adw->sim),
153440024Sgibbs				target, CAM_LUN_WILDCARD);
153540024Sgibbs
153640024Sgibbs	if (error == CAM_REQ_CMP) {
153740024Sgibbs		xpt_async(AC_SENT_BDR, path, NULL);
153840024Sgibbs		xpt_free_path(path);
153940024Sgibbs	}
154040024Sgibbs	adw->last_reset = CAM_BDR_SENT;
154140024Sgibbs}
154240024Sgibbs
154340024Sgibbsstatic void
154440024Sgibbsadw_handle_bus_reset(struct adw_softc *adw, int initiated)
154540024Sgibbs{
154640024Sgibbs	if (initiated) {
154740024Sgibbs		/*
154840024Sgibbs		 * The microcode currently sets the SCSI Bus Reset signal
154940024Sgibbs		 * while handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET
155040024Sgibbs		 * command above.  But the SCSI Bus Reset Hold Time in the
155140024Sgibbs		 * microcode is not deterministic (it may in fact be for less
155240024Sgibbs		 * than the SCSI Spec. minimum of 25 us).  Therefore on return
155340024Sgibbs		 * the Adv Library sets the SCSI Bus Reset signal for
155440024Sgibbs		 * ADW_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
155540024Sgibbs		 * than 25 us.
155640024Sgibbs		 */
155740024Sgibbs		u_int scsi_ctrl;
155840024Sgibbs
155940024Sgibbs	    	scsi_ctrl = adw_inw(adw, ADW_SCSI_CTRL) & ~ADW_SCSI_CTRL_RSTOUT;
156040024Sgibbs		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl | ADW_SCSI_CTRL_RSTOUT);
156140024Sgibbs		DELAY(ADW_SCSI_RESET_HOLD_TIME_US);
156240024Sgibbs		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl);
156340024Sgibbs
156440024Sgibbs		/*
156540024Sgibbs		 * We will perform the async notification when the
156640024Sgibbs		 * SCSI Reset interrupt occurs.
156740024Sgibbs		 */
156840024Sgibbs	} else
156940024Sgibbs		xpt_async(AC_BUS_RESET, adw->path, NULL);
157040024Sgibbs	adw->last_reset = CAM_SCSI_BUS_RESET;
157140024Sgibbs}
1572