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: releng/10.3/sys/dev/advansys/adwcam.c 281826 2015-04-21 11:27:50Z mav $");
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
7840024Sgibbsstatic __inline struct acb*	adwgetacb(struct adw_softc *adw);
7940024Sgibbsstatic __inline void		adwfreeacb(struct adw_softc *adw,
8040024Sgibbs					   struct acb *acb);
8140024Sgibbs
8240024Sgibbsstatic void		adwmapmem(void *arg, bus_dma_segment_t *segs,
8340024Sgibbs				  int nseg, int error);
8440024Sgibbsstatic struct sg_map_node*
8540024Sgibbs			adwallocsgmap(struct adw_softc *adw);
8640024Sgibbsstatic int		adwallocacbs(struct adw_softc *adw);
8740024Sgibbs
8840024Sgibbsstatic void		adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs,
8940024Sgibbs				      int nseg, int error);
9040024Sgibbsstatic void		adw_action(struct cam_sim *sim, union ccb *ccb);
91241588Sjhbstatic void		adw_intr_locked(struct adw_softc *adw);
9240024Sgibbsstatic void		adw_poll(struct cam_sim *sim);
9340024Sgibbsstatic void		adw_async(void *callback_arg, u_int32_t code,
9440024Sgibbs				  struct cam_path *path, void *arg);
9540024Sgibbsstatic void		adwprocesserror(struct adw_softc *adw, struct acb *acb);
9640024Sgibbsstatic void		adwtimeout(void *arg);
9740024Sgibbsstatic void		adw_handle_device_reset(struct adw_softc *adw,
9840024Sgibbs						u_int target);
9940024Sgibbsstatic void		adw_handle_bus_reset(struct adw_softc *adw,
10040024Sgibbs					     int initiated);
10140024Sgibbs
10240024Sgibbsstatic __inline struct acb*
10340024Sgibbsadwgetacb(struct adw_softc *adw)
10440024Sgibbs{
10540024Sgibbs	struct	acb* acb;
10640024Sgibbs
107241588Sjhb	if (!dumping)
108241588Sjhb		mtx_assert(&adw->lock, MA_OWNED);
10940024Sgibbs	if ((acb = SLIST_FIRST(&adw->free_acb_list)) != NULL) {
11040024Sgibbs		SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
11140024Sgibbs	} else if (adw->num_acbs < adw->max_acbs) {
11240024Sgibbs		adwallocacbs(adw);
11340024Sgibbs		acb = SLIST_FIRST(&adw->free_acb_list);
11440024Sgibbs		if (acb == NULL)
115241588Sjhb			device_printf(adw->device, "Can't malloc ACB\n");
11640024Sgibbs		else {
11740024Sgibbs			SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
11840024Sgibbs		}
11940024Sgibbs	}
12040024Sgibbs
12140024Sgibbs	return (acb);
12240024Sgibbs}
12340024Sgibbs
12440024Sgibbsstatic __inline void
12540024Sgibbsadwfreeacb(struct adw_softc *adw, struct acb *acb)
12640024Sgibbs{
12740024Sgibbs
128241588Sjhb	if (!dumping)
129241588Sjhb		mtx_assert(&adw->lock, MA_OWNED);
13040024Sgibbs	if ((acb->state & ACB_ACTIVE) != 0)
13140024Sgibbs		LIST_REMOVE(&acb->ccb->ccb_h, sim_links.le);
13240024Sgibbs	if ((acb->state & ACB_RELEASE_SIMQ) != 0)
13340024Sgibbs		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
13440024Sgibbs	else if ((adw->state & ADW_RESOURCE_SHORTAGE) != 0
13540024Sgibbs	      && (acb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
13640024Sgibbs		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
13740024Sgibbs		adw->state &= ~ADW_RESOURCE_SHORTAGE;
13840024Sgibbs	}
13940024Sgibbs	acb->state = ACB_FREE;
14040024Sgibbs	SLIST_INSERT_HEAD(&adw->free_acb_list, acb, links);
14140024Sgibbs}
14240024Sgibbs
14340024Sgibbsstatic void
14440024Sgibbsadwmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
14540024Sgibbs{
14640024Sgibbs	bus_addr_t *busaddrp;
14740024Sgibbs
14840024Sgibbs	busaddrp = (bus_addr_t *)arg;
14940024Sgibbs	*busaddrp = segs->ds_addr;
15040024Sgibbs}
15140024Sgibbs
15240024Sgibbsstatic struct sg_map_node *
15340024Sgibbsadwallocsgmap(struct adw_softc *adw)
15440024Sgibbs{
15540024Sgibbs	struct sg_map_node *sg_map;
15640024Sgibbs
15740024Sgibbs	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
15840024Sgibbs
15940024Sgibbs	if (sg_map == NULL)
16040024Sgibbs		return (NULL);
16140024Sgibbs
16240024Sgibbs	/* Allocate S/G space for the next batch of ACBS */
16340024Sgibbs	if (bus_dmamem_alloc(adw->sg_dmat, (void **)&sg_map->sg_vaddr,
16440024Sgibbs			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
16540024Sgibbs		free(sg_map, M_DEVBUF);
16640024Sgibbs		return (NULL);
16740024Sgibbs	}
16840024Sgibbs
16940024Sgibbs	SLIST_INSERT_HEAD(&adw->sg_maps, sg_map, links);
17040024Sgibbs
17140024Sgibbs	bus_dmamap_load(adw->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
17240024Sgibbs			PAGE_SIZE, adwmapmem, &sg_map->sg_physaddr, /*flags*/0);
17340024Sgibbs
17440024Sgibbs	bzero(sg_map->sg_vaddr, PAGE_SIZE);
17540024Sgibbs	return (sg_map);
17640024Sgibbs}
17740024Sgibbs
17840024Sgibbs/*
17940024Sgibbs * Allocate another chunk of CCB's. Return count of entries added.
18040024Sgibbs */
18140024Sgibbsstatic int
18240024Sgibbsadwallocacbs(struct adw_softc *adw)
18340024Sgibbs{
18440024Sgibbs	struct acb *next_acb;
18540024Sgibbs	struct sg_map_node *sg_map;
18640024Sgibbs	bus_addr_t busaddr;
18740024Sgibbs	struct adw_sg_block *blocks;
18840024Sgibbs	int newcount;
18940024Sgibbs	int i;
19040024Sgibbs
19140024Sgibbs	next_acb = &adw->acbs[adw->num_acbs];
19240024Sgibbs	sg_map = adwallocsgmap(adw);
19340024Sgibbs
19440024Sgibbs	if (sg_map == NULL)
19540024Sgibbs		return (0);
19640024Sgibbs
19740024Sgibbs	blocks = sg_map->sg_vaddr;
19840024Sgibbs	busaddr = sg_map->sg_physaddr;
19940024Sgibbs
20040024Sgibbs	newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks)));
20140024Sgibbs	for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) {
20240024Sgibbs		int error;
20340024Sgibbs
20440024Sgibbs		error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0,
20540024Sgibbs					  &next_acb->dmamap);
20640024Sgibbs		if (error != 0)
20740024Sgibbs			break;
20856979Sgibbs		next_acb->queue.scsi_req_baddr = acbvtob(adw, next_acb);
20956979Sgibbs		next_acb->queue.scsi_req_bo = acbvtobo(adw, next_acb);
21056979Sgibbs		next_acb->queue.sense_baddr =
21156979Sgibbs		    acbvtob(adw, next_acb) + offsetof(struct acb, sense_data);
21240024Sgibbs		next_acb->sg_blocks = blocks;
21340024Sgibbs		next_acb->sg_busaddr = busaddr;
21440024Sgibbs		next_acb->state = ACB_FREE;
215241588Sjhb		callout_init_mtx(&next_acb->timer, &adw->lock, 0);
21640024Sgibbs		SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links);
21740024Sgibbs		blocks += ADW_SG_BLOCKCNT;
21840024Sgibbs		busaddr += ADW_SG_BLOCKCNT * sizeof(*blocks);
21940024Sgibbs		next_acb++;
22040024Sgibbs		adw->num_acbs++;
22140024Sgibbs	}
22240024Sgibbs	return (i);
22340024Sgibbs}
22440024Sgibbs
22540024Sgibbsstatic void
22640024Sgibbsadwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
22740024Sgibbs{
22840024Sgibbs	struct	 acb *acb;
22940024Sgibbs	union	 ccb *ccb;
23040024Sgibbs	struct	 adw_softc *adw;
23140024Sgibbs
23240024Sgibbs	acb = (struct acb *)arg;
23340024Sgibbs	ccb = acb->ccb;
23440024Sgibbs	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
23540024Sgibbs
236241588Sjhb	if (!dumping)
237241588Sjhb		mtx_assert(&adw->lock, MA_OWNED);
23840024Sgibbs	if (error != 0) {
23940024Sgibbs		if (error != EFBIG)
240241588Sjhb			device_printf(adw->device, "Unexepected error 0x%x "
241241588Sjhb			    "returned from bus_dmamap_load\n", error);
24240024Sgibbs		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
24340024Sgibbs			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
24440024Sgibbs			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
24540024Sgibbs		}
24640024Sgibbs		adwfreeacb(adw, acb);
24740024Sgibbs		xpt_done(ccb);
24840024Sgibbs		return;
24940024Sgibbs	}
25040024Sgibbs
25140024Sgibbs	if (nseg != 0) {
252115343Sscottl		bus_dmasync_op_t op;
25340024Sgibbs
25440024Sgibbs		acb->queue.data_addr = dm_segs[0].ds_addr;
25540024Sgibbs		acb->queue.data_cnt = ccb->csio.dxfer_len;
25640024Sgibbs		if (nseg > 1) {
25740024Sgibbs			struct adw_sg_block *sg_block;
25840024Sgibbs			struct adw_sg_elm *sg;
25940024Sgibbs			bus_addr_t sg_busaddr;
26040024Sgibbs			u_int sg_index;
26140024Sgibbs			bus_dma_segment_t *end_seg;
26240024Sgibbs
26340024Sgibbs			end_seg = dm_segs + nseg;
26440024Sgibbs
26540024Sgibbs			sg_busaddr = acb->sg_busaddr;
26640024Sgibbs			sg_index = 0;
26740024Sgibbs			/* Copy the segments into our SG list */
26840024Sgibbs			for (sg_block = acb->sg_blocks;; sg_block++) {
26956979Sgibbs				u_int i;
27040024Sgibbs
27140024Sgibbs				sg = sg_block->sg_list;
27256979Sgibbs				for (i = 0; i < ADW_NO_OF_SG_PER_BLOCK; i++) {
27356979Sgibbs					if (dm_segs >= end_seg)
27456979Sgibbs						break;
27556979Sgibbs
27640024Sgibbs					sg->sg_addr = dm_segs->ds_addr;
27740024Sgibbs					sg->sg_count = dm_segs->ds_len;
27840024Sgibbs					sg++;
27940024Sgibbs					dm_segs++;
28040024Sgibbs				}
28156979Sgibbs				sg_block->sg_cnt = i;
28256979Sgibbs				sg_index += i;
28340024Sgibbs				if (dm_segs == end_seg) {
28440024Sgibbs					sg_block->sg_busaddr_next = 0;
28540024Sgibbs					break;
28640024Sgibbs				} else {
28740024Sgibbs					sg_busaddr +=
28840024Sgibbs					    sizeof(struct adw_sg_block);
28940024Sgibbs					sg_block->sg_busaddr_next = sg_busaddr;
29040024Sgibbs				}
29140024Sgibbs			}
29240024Sgibbs			acb->queue.sg_real_addr = acb->sg_busaddr;
29340024Sgibbs		} else {
29440024Sgibbs			acb->queue.sg_real_addr = 0;
29540024Sgibbs		}
29640024Sgibbs
29740024Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
29840024Sgibbs			op = BUS_DMASYNC_PREREAD;
29940024Sgibbs		else
30040024Sgibbs			op = BUS_DMASYNC_PREWRITE;
30140024Sgibbs
30240024Sgibbs		bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
30340024Sgibbs
30440024Sgibbs	} else {
30540024Sgibbs		acb->queue.data_addr = 0;
30640024Sgibbs		acb->queue.data_cnt = 0;
30740024Sgibbs		acb->queue.sg_real_addr = 0;
30840024Sgibbs	}
30940024Sgibbs
31040024Sgibbs	/*
31140024Sgibbs	 * Last time we need to check if this CCB needs to
31240024Sgibbs	 * be aborted.
31340024Sgibbs	 */
31440024Sgibbs	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
31540024Sgibbs		if (nseg != 0)
31640024Sgibbs			bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
31740024Sgibbs		adwfreeacb(adw, acb);
31840024Sgibbs		xpt_done(ccb);
31940024Sgibbs		return;
32040024Sgibbs	}
32157679Sgibbs
32240024Sgibbs	acb->state |= ACB_ACTIVE;
32340024Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
32440024Sgibbs	LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le);
325275982Ssmh	callout_reset_sbt(&acb->timer, SBT_1MS * ccb->ccb_h.timeout, 0,
326275982Ssmh	    adwtimeout, acb, 0);
32740024Sgibbs
32856979Sgibbs	adw_send_acb(adw, acb, acbvtob(adw, acb));
32940024Sgibbs}
33040024Sgibbs
33140024Sgibbsstatic void
33240024Sgibbsadw_action(struct cam_sim *sim, union ccb *ccb)
33340024Sgibbs{
33440024Sgibbs	struct	adw_softc *adw;
33540024Sgibbs
33640024Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adw_action\n"));
33740024Sgibbs
33840024Sgibbs	adw = (struct adw_softc *)cam_sim_softc(sim);
339241588Sjhb	if (!dumping)
340241588Sjhb		mtx_assert(&adw->lock, MA_OWNED);
34140024Sgibbs
34240024Sgibbs	switch (ccb->ccb_h.func_code) {
34340024Sgibbs	/* Common cases first */
34440024Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
34540024Sgibbs	{
34640024Sgibbs		struct	ccb_scsiio *csio;
34740024Sgibbs		struct	ccb_hdr *ccbh;
34840024Sgibbs		struct	acb *acb;
349246713Skib		int error;
35040024Sgibbs
35140024Sgibbs		csio = &ccb->csio;
35240024Sgibbs		ccbh = &ccb->ccb_h;
35356979Sgibbs
35440024Sgibbs		/* Max supported CDB length is 12 bytes */
35540024Sgibbs		if (csio->cdb_len > 12) {
35640024Sgibbs			ccb->ccb_h.status = CAM_REQ_INVALID;
35740024Sgibbs			xpt_done(ccb);
35840024Sgibbs			return;
35940024Sgibbs		}
36040024Sgibbs
36140024Sgibbs		if ((acb = adwgetacb(adw)) == NULL) {
36240024Sgibbs			adw->state |= ADW_RESOURCE_SHORTAGE;
36340024Sgibbs			xpt_freeze_simq(sim, /*count*/1);
36440024Sgibbs			ccb->ccb_h.status = CAM_REQUEUE_REQ;
36540024Sgibbs			xpt_done(ccb);
36640024Sgibbs			return;
36740024Sgibbs		}
36840024Sgibbs
36956979Sgibbs		/* Link acb and ccb so we can find one from the other */
37040024Sgibbs		acb->ccb = ccb;
37140024Sgibbs		ccb->ccb_h.ccb_acb_ptr = acb;
37240024Sgibbs		ccb->ccb_h.ccb_adw_ptr = adw;
37340024Sgibbs
37440024Sgibbs		acb->queue.cntl = 0;
37556979Sgibbs		acb->queue.target_cmd = 0;
37640024Sgibbs		acb->queue.target_id = ccb->ccb_h.target_id;
37740024Sgibbs		acb->queue.target_lun = ccb->ccb_h.target_lun;
37840024Sgibbs
37956979Sgibbs		acb->queue.mflag = 0;
38040024Sgibbs		acb->queue.sense_len =
38140024Sgibbs			MIN(csio->sense_len, sizeof(acb->sense_data));
38240024Sgibbs		acb->queue.cdb_len = csio->cdb_len;
38356979Sgibbs		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
38456979Sgibbs			switch (csio->tag_action) {
38556979Sgibbs			case MSG_SIMPLE_Q_TAG:
38657679Sgibbs				acb->queue.scsi_cntl = ADW_QSC_SIMPLE_Q_TAG;
38756979Sgibbs				break;
38856979Sgibbs			case MSG_HEAD_OF_Q_TAG:
38956979Sgibbs				acb->queue.scsi_cntl = ADW_QSC_HEAD_OF_Q_TAG;
39056979Sgibbs				break;
39156979Sgibbs			case MSG_ORDERED_Q_TAG:
39256979Sgibbs				acb->queue.scsi_cntl = ADW_QSC_ORDERED_Q_TAG;
39356979Sgibbs				break;
39457679Sgibbs			default:
39557679Sgibbs				acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
39657679Sgibbs				break;
39756979Sgibbs			}
39856979Sgibbs		} else
39956979Sgibbs			acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
40040024Sgibbs
40156979Sgibbs		if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
40256979Sgibbs			acb->queue.scsi_cntl |= ADW_QSC_NO_DISC;
40340024Sgibbs
40440024Sgibbs		acb->queue.done_status = 0;
40540024Sgibbs		acb->queue.scsi_status = 0;
40640024Sgibbs		acb->queue.host_status = 0;
40756979Sgibbs		acb->queue.sg_wk_ix = 0;
40840024Sgibbs		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
40940024Sgibbs			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
41040024Sgibbs				bcopy(csio->cdb_io.cdb_ptr,
41140024Sgibbs				      acb->queue.cdb, csio->cdb_len);
41240024Sgibbs			} else {
41340024Sgibbs				/* I guess I could map it in... */
41440024Sgibbs				ccb->ccb_h.status = CAM_REQ_INVALID;
41540024Sgibbs				adwfreeacb(adw, acb);
41640024Sgibbs				xpt_done(ccb);
41740024Sgibbs				return;
41840024Sgibbs			}
41940024Sgibbs		} else {
42040024Sgibbs			bcopy(csio->cdb_io.cdb_bytes,
42140024Sgibbs			      acb->queue.cdb, csio->cdb_len);
42240024Sgibbs		}
42340024Sgibbs
424246713Skib		error = bus_dmamap_load_ccb(adw->buffer_dmat,
425246713Skib					    acb->dmamap,
426246713Skib					    ccb,
427246713Skib					    adwexecuteacb,
428246713Skib					    acb, /*flags*/0);
429246713Skib		if (error == EINPROGRESS) {
430246713Skib			/*
431246713Skib			 * So as to maintain ordering, freeze the controller
432246713Skib			 * queue until our mapping is returned.
433246713Skib			 */
434246713Skib			xpt_freeze_simq(sim, 1);
435246713Skib			acb->state |= CAM_RELEASE_SIMQ;
43640024Sgibbs		}
43740024Sgibbs		break;
43840024Sgibbs	}
43940024Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
44040024Sgibbs	{
44140024Sgibbs		adw_idle_cmd_status_t status;
44240024Sgibbs
44357679Sgibbs		status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
44457679Sgibbs					   ccb->ccb_h.target_id);
44540024Sgibbs		if (status == ADW_IDLE_CMD_SUCCESS) {
44640024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
44740024Sgibbs			if (bootverbose) {
44840024Sgibbs				xpt_print_path(ccb->ccb_h.path);
44940024Sgibbs				printf("BDR Delivered\n");
45040024Sgibbs			}
45140024Sgibbs		} else
45240024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
45340024Sgibbs		xpt_done(ccb);
45440024Sgibbs		break;
45540024Sgibbs	}
45640024Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
45740024Sgibbs		/* XXX Implement */
45840024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
45940024Sgibbs		xpt_done(ccb);
46040024Sgibbs		break;
46140024Sgibbs	case XPT_SET_TRAN_SETTINGS:
46240024Sgibbs	{
463163816Smjacob		struct ccb_trans_settings_scsi *scsi;
464163816Smjacob		struct ccb_trans_settings_spi *spi;
46540024Sgibbs		struct	  ccb_trans_settings *cts;
46640024Sgibbs		u_int	  target_mask;
46740024Sgibbs
46840024Sgibbs		cts = &ccb->cts;
46940024Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
47040024Sgibbs
471163816Smjacob		scsi = &cts->proto_specific.scsi;
472163816Smjacob		spi = &cts->xport_specific.spi;
473163816Smjacob		if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
474163816Smjacob			u_int sdtrdone;
475163816Smjacob
476163816Smjacob			sdtrdone = adw_lram_read_16(adw, ADW_MC_SDTR_DONE);
477163816Smjacob			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
478163816Smjacob				u_int discenb;
479163816Smjacob
480163816Smjacob				discenb =
481163816Smjacob				    adw_lram_read_16(adw, ADW_MC_DISC_ENABLE);
482163816Smjacob
483163816Smjacob				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
484163816Smjacob					discenb |= target_mask;
485163816Smjacob				else
486163816Smjacob					discenb &= ~target_mask;
487163816Smjacob
488163816Smjacob				adw_lram_write_16(adw, ADW_MC_DISC_ENABLE,
489163816Smjacob						  discenb);
490163816Smjacob			}
491163816Smjacob
492163816Smjacob			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
493163816Smjacob
494163816Smjacob				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
495163816Smjacob					adw->tagenb |= target_mask;
496163816Smjacob				else
497163816Smjacob					adw->tagenb &= ~target_mask;
498163816Smjacob			}
499163816Smjacob
500163816Smjacob			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
501163816Smjacob				u_int wdtrenb_orig;
502163816Smjacob				u_int wdtrenb;
503163816Smjacob				u_int wdtrdone;
504163816Smjacob
505163816Smjacob				wdtrenb_orig =
506163816Smjacob				    adw_lram_read_16(adw, ADW_MC_WDTR_ABLE);
507163816Smjacob				wdtrenb = wdtrenb_orig;
508163816Smjacob				wdtrdone = adw_lram_read_16(adw,
509163816Smjacob							    ADW_MC_WDTR_DONE);
510163816Smjacob				switch (spi->bus_width) {
511163816Smjacob				case MSG_EXT_WDTR_BUS_32_BIT:
512163816Smjacob				case MSG_EXT_WDTR_BUS_16_BIT:
513163816Smjacob					wdtrenb |= target_mask;
514163816Smjacob					break;
515163816Smjacob				case MSG_EXT_WDTR_BUS_8_BIT:
516163816Smjacob				default:
517163816Smjacob					wdtrenb &= ~target_mask;
518163816Smjacob					break;
519163816Smjacob				}
520163816Smjacob				if (wdtrenb != wdtrenb_orig) {
521163816Smjacob					adw_lram_write_16(adw,
522163816Smjacob							  ADW_MC_WDTR_ABLE,
523163816Smjacob							  wdtrenb);
524163816Smjacob					wdtrdone &= ~target_mask;
525163816Smjacob					adw_lram_write_16(adw,
526163816Smjacob							  ADW_MC_WDTR_DONE,
527163816Smjacob							  wdtrdone);
528163816Smjacob					/* Wide negotiation forces async */
529163816Smjacob					sdtrdone &= ~target_mask;
530163816Smjacob					adw_lram_write_16(adw,
531163816Smjacob							  ADW_MC_SDTR_DONE,
532163816Smjacob							  sdtrdone);
533163816Smjacob				}
534163816Smjacob			}
535163816Smjacob
536163816Smjacob			if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0)
537163816Smjacob			 || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) {
538163816Smjacob				u_int sdtr_orig;
539163816Smjacob				u_int sdtr;
540163816Smjacob				u_int sdtrable_orig;
541163816Smjacob				u_int sdtrable;
542163816Smjacob
543163816Smjacob				sdtr = adw_get_chip_sdtr(adw,
544163816Smjacob							 ccb->ccb_h.target_id);
545163816Smjacob				sdtr_orig = sdtr;
546163816Smjacob				sdtrable = adw_lram_read_16(adw,
547163816Smjacob							    ADW_MC_SDTR_ABLE);
548163816Smjacob				sdtrable_orig = sdtrable;
549163816Smjacob
550163816Smjacob				if ((spi->valid
551163816Smjacob				   & CTS_SPI_VALID_SYNC_RATE) != 0) {
552163816Smjacob
553163816Smjacob					sdtr =
554163816Smjacob					    adw_find_sdtr(adw,
555163816Smjacob							  spi->sync_period);
556163816Smjacob				}
557163816Smjacob
558163816Smjacob				if ((spi->valid
559163816Smjacob				   & CTS_SPI_VALID_SYNC_OFFSET) != 0) {
560163816Smjacob					if (spi->sync_offset == 0)
561163816Smjacob						sdtr = ADW_MC_SDTR_ASYNC;
562163816Smjacob				}
563163816Smjacob
564163816Smjacob				if (sdtr == ADW_MC_SDTR_ASYNC)
565163816Smjacob					sdtrable &= ~target_mask;
566163816Smjacob				else
567163816Smjacob					sdtrable |= target_mask;
568163816Smjacob				if (sdtr != sdtr_orig
569163816Smjacob				 || sdtrable != sdtrable_orig) {
570163816Smjacob					adw_set_chip_sdtr(adw,
571163816Smjacob							  ccb->ccb_h.target_id,
572163816Smjacob							  sdtr);
573163816Smjacob					sdtrdone &= ~target_mask;
574163816Smjacob					adw_lram_write_16(adw, ADW_MC_SDTR_ABLE,
575163816Smjacob							  sdtrable);
576163816Smjacob					adw_lram_write_16(adw, ADW_MC_SDTR_DONE,
577163816Smjacob							  sdtrdone);
578163816Smjacob
579163816Smjacob				}
580163816Smjacob			}
581163816Smjacob		}
58240024Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
58340024Sgibbs		xpt_done(ccb);
58440024Sgibbs		break;
58540024Sgibbs	}
58640024Sgibbs	case XPT_GET_TRAN_SETTINGS:
58740024Sgibbs	/* Get default/user set transfer settings for the target */
58840024Sgibbs	{
589163816Smjacob		struct ccb_trans_settings_scsi *scsi;
590163816Smjacob		struct ccb_trans_settings_spi *spi;
59140024Sgibbs		struct	ccb_trans_settings *cts;
59240024Sgibbs		u_int	target_mask;
59340024Sgibbs
59440024Sgibbs		cts = &ccb->cts;
59540024Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
596163816Smjacob		cts->protocol = PROTO_SCSI;
597163816Smjacob		cts->protocol_version = SCSI_REV_2;
598163816Smjacob		cts->transport = XPORT_SPI;
599163816Smjacob		cts->transport_version = 2;
600163816Smjacob
601163816Smjacob		scsi = &cts->proto_specific.scsi;
602163816Smjacob		spi = &cts->xport_specific.spi;
603163816Smjacob		if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
60456979Sgibbs			u_int mc_sdtr;
60556979Sgibbs
606163816Smjacob			spi->flags = 0;
607163816Smjacob			if ((adw->user_discenb & target_mask) != 0)
608163816Smjacob				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
609163816Smjacob
610163816Smjacob			if ((adw->user_tagenb & target_mask) != 0)
611163816Smjacob				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
612163816Smjacob
613163816Smjacob			if ((adw->user_wdtr & target_mask) != 0)
614163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
615163816Smjacob			else
616163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
617163816Smjacob
618163816Smjacob			mc_sdtr = adw_get_user_sdtr(adw, ccb->ccb_h.target_id);
619163816Smjacob			spi->sync_period = adw_find_period(adw, mc_sdtr);
620163816Smjacob			if (spi->sync_period != 0)
621163816Smjacob				spi->sync_offset = 15; /* XXX ??? */
622163816Smjacob			else
623163816Smjacob				spi->sync_offset = 0;
624163816Smjacob
625163816Smjacob
626163816Smjacob		} else {
627163816Smjacob			u_int targ_tinfo;
628163816Smjacob
629163816Smjacob			spi->flags = 0;
630163816Smjacob			if ((adw_lram_read_16(adw, ADW_MC_DISC_ENABLE)
631163816Smjacob			  & target_mask) != 0)
632163816Smjacob				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
633163816Smjacob
634163816Smjacob			if ((adw->tagenb & target_mask) != 0)
635163816Smjacob				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
636163816Smjacob
637163816Smjacob			targ_tinfo =
638163816Smjacob			    adw_lram_read_16(adw,
639163816Smjacob					     ADW_MC_DEVICE_HSHK_CFG_TABLE
640163816Smjacob					     + (2 * ccb->ccb_h.target_id));
641163816Smjacob
642163816Smjacob			if ((targ_tinfo & ADW_HSHK_CFG_WIDE_XFR) != 0)
643163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
644163816Smjacob			else
645163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
646163816Smjacob
647163816Smjacob			spi->sync_period =
648163816Smjacob			    adw_hshk_cfg_period_factor(targ_tinfo);
649163816Smjacob
650163816Smjacob			spi->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET;
651163816Smjacob			if (spi->sync_period == 0)
652163816Smjacob				spi->sync_offset = 0;
653163816Smjacob
654163816Smjacob			if (spi->sync_offset == 0)
655163816Smjacob				spi->sync_period = 0;
656163816Smjacob		}
657163816Smjacob
658163816Smjacob		spi->valid = CTS_SPI_VALID_SYNC_RATE
659163816Smjacob			   | CTS_SPI_VALID_SYNC_OFFSET
660163816Smjacob			   | CTS_SPI_VALID_BUS_WIDTH
661163816Smjacob			   | CTS_SPI_VALID_DISC;
662163816Smjacob		scsi->valid = CTS_SCSI_VALID_TQ;
66340024Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
66440024Sgibbs		xpt_done(ccb);
66540024Sgibbs		break;
66640024Sgibbs	}
66740024Sgibbs	case XPT_CALC_GEOMETRY:
66840024Sgibbs	{
66940024Sgibbs		/*
67040024Sgibbs		 * XXX Use Adaptec translation until I find out how to
67140024Sgibbs		 *     get this information from the card.
67240024Sgibbs		 */
673116351Snjl		cam_calc_geometry(&ccb->ccg, /*extended*/1);
67440024Sgibbs		xpt_done(ccb);
67540024Sgibbs		break;
67640024Sgibbs	}
67740024Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
67840024Sgibbs	{
67957679Sgibbs		int failure;
68040024Sgibbs
68157679Sgibbs		failure = adw_reset_bus(adw);
68257679Sgibbs		if (failure != 0) {
68340024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
68457679Sgibbs		} else {
68557679Sgibbs			if (bootverbose) {
68657679Sgibbs				xpt_print_path(adw->path);
68757679Sgibbs				printf("Bus Reset Delivered\n");
68857679Sgibbs			}
68957679Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
69056979Sgibbs		}
69140024Sgibbs		xpt_done(ccb);
69240024Sgibbs		break;
69340024Sgibbs	}
69440024Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
69540024Sgibbs		/* XXX Implement */
69640024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
69740024Sgibbs		xpt_done(ccb);
69840024Sgibbs		break;
69940024Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
70040024Sgibbs	{
70140024Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
70240024Sgibbs
70340024Sgibbs		cpi->version_num = 1;
70440024Sgibbs		cpi->hba_inquiry = PI_WIDE_16|PI_SDTR_ABLE|PI_TAG_ABLE;
70540024Sgibbs		cpi->target_sprt = 0;
70640024Sgibbs		cpi->hba_misc = 0;
70740024Sgibbs		cpi->hba_eng_cnt = 0;
70840024Sgibbs		cpi->max_target = ADW_MAX_TID;
70940024Sgibbs		cpi->max_lun = ADW_MAX_LUN;
71040024Sgibbs		cpi->initiator_id = adw->initiator_id;
71140024Sgibbs		cpi->bus_id = cam_sim_bus(sim);
71246581Sken		cpi->base_transfer_speed = 3300;
71340024Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
71440024Sgibbs		strncpy(cpi->hba_vid, "AdvanSys", HBA_IDLEN);
71540024Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
71640024Sgibbs		cpi->unit_number = cam_sim_unit(sim);
717163816Smjacob                cpi->transport = XPORT_SPI;
718163816Smjacob                cpi->transport_version = 2;
719163816Smjacob                cpi->protocol = PROTO_SCSI;
720163816Smjacob                cpi->protocol_version = SCSI_REV_2;
72140024Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
72240024Sgibbs		xpt_done(ccb);
72340024Sgibbs		break;
72440024Sgibbs	}
72540024Sgibbs	default:
72640024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
72740024Sgibbs		xpt_done(ccb);
72840024Sgibbs		break;
72940024Sgibbs	}
73040024Sgibbs}
73140024Sgibbs
73240024Sgibbsstatic void
73340024Sgibbsadw_poll(struct cam_sim *sim)
73440024Sgibbs{
735241588Sjhb	adw_intr_locked(cam_sim_softc(sim));
73640024Sgibbs}
73740024Sgibbs
73840024Sgibbsstatic void
73940024Sgibbsadw_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
74040024Sgibbs{
74140024Sgibbs}
74240024Sgibbs
74340024Sgibbsstruct adw_softc *
74456979Sgibbsadw_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id)
74540024Sgibbs{
74640024Sgibbs	struct	 adw_softc *adw;
747241588Sjhb
748241588Sjhb	adw = device_get_softc(dev);
74940024Sgibbs	LIST_INIT(&adw->pending_ccbs);
75040024Sgibbs	SLIST_INIT(&adw->sg_maps);
751241588Sjhb	mtx_init(&adw->lock, "adw", NULL, MTX_DEF);
75256979Sgibbs	adw->device = dev;
75356979Sgibbs	adw->regs_res_type = regs_type;
75456979Sgibbs	adw->regs_res_id = regs_id;
75556979Sgibbs	adw->regs = regs;
75640024Sgibbs	return(adw);
75740024Sgibbs}
75840024Sgibbs
75940024Sgibbsvoid
76040024Sgibbsadw_free(struct adw_softc *adw)
76140024Sgibbs{
76240024Sgibbs	switch (adw->init_level) {
76356979Sgibbs	case 9:
76440024Sgibbs	{
76540024Sgibbs		struct sg_map_node *sg_map;
76640024Sgibbs
76740024Sgibbs		while ((sg_map = SLIST_FIRST(&adw->sg_maps)) != NULL) {
76840024Sgibbs			SLIST_REMOVE_HEAD(&adw->sg_maps, links);
76940024Sgibbs			bus_dmamap_unload(adw->sg_dmat,
77040024Sgibbs					  sg_map->sg_dmamap);
77140024Sgibbs			bus_dmamem_free(adw->sg_dmat, sg_map->sg_vaddr,
77240024Sgibbs					sg_map->sg_dmamap);
77340024Sgibbs			free(sg_map, M_DEVBUF);
77440024Sgibbs		}
77540024Sgibbs		bus_dma_tag_destroy(adw->sg_dmat);
77640024Sgibbs	}
77756979Sgibbs	case 8:
77840024Sgibbs		bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap);
77956979Sgibbs	case 7:
78040024Sgibbs		bus_dmamem_free(adw->acb_dmat, adw->acbs,
78140024Sgibbs				adw->acb_dmamap);
78240024Sgibbs		bus_dmamap_destroy(adw->acb_dmat, adw->acb_dmamap);
78356979Sgibbs	case 6:
78456979Sgibbs		bus_dma_tag_destroy(adw->acb_dmat);
78556979Sgibbs	case 5:
78656979Sgibbs		bus_dmamap_unload(adw->carrier_dmat, adw->carrier_dmamap);
78756979Sgibbs	case 4:
78856979Sgibbs		bus_dmamem_free(adw->carrier_dmat, adw->carriers,
78956979Sgibbs				adw->carrier_dmamap);
79056979Sgibbs		bus_dmamap_destroy(adw->carrier_dmat, adw->carrier_dmamap);
79140024Sgibbs	case 3:
79256979Sgibbs		bus_dma_tag_destroy(adw->carrier_dmat);
79340024Sgibbs	case 2:
79440024Sgibbs		bus_dma_tag_destroy(adw->buffer_dmat);
79540024Sgibbs	case 1:
79640024Sgibbs		bus_dma_tag_destroy(adw->parent_dmat);
79740024Sgibbs	case 0:
79840024Sgibbs		break;
79940024Sgibbs	}
800138502Srsm
801138502Srsm	if (adw->regs != NULL)
802138502Srsm		bus_release_resource(adw->device,
803138502Srsm				     adw->regs_res_type,
804138502Srsm				     adw->regs_res_id,
805138502Srsm				     adw->regs);
806138502Srsm
807138502Srsm	if (adw->irq != NULL)
808138502Srsm		bus_release_resource(adw->device,
809138502Srsm				     adw->irq_res_type,
810138502Srsm				     0, adw->irq);
811138502Srsm
812138502Srsm	if (adw->sim != NULL) {
813138502Srsm		if (adw->path != NULL) {
814138502Srsm			xpt_async(AC_LOST_DEVICE, adw->path, NULL);
815138502Srsm			xpt_free_path(adw->path);
816138502Srsm		}
817138502Srsm		xpt_bus_deregister(cam_sim_path(adw->sim));
818138502Srsm		cam_sim_free(adw->sim, /*free_devq*/TRUE);
819138502Srsm	}
820241588Sjhb	mtx_destroy(&adw->lock);
82140024Sgibbs}
82240024Sgibbs
82340024Sgibbsint
82440024Sgibbsadw_init(struct adw_softc *adw)
82540024Sgibbs{
82640024Sgibbs	struct	  adw_eeprom eep_config;
82756979Sgibbs	u_int	  tid;
82856979Sgibbs	u_int	  i;
82940024Sgibbs	u_int16_t checksum;
83040024Sgibbs	u_int16_t scsicfg1;
83140024Sgibbs
83240024Sgibbs	checksum = adw_eeprom_read(adw, &eep_config);
83340024Sgibbs	bcopy(eep_config.serial_number, adw->serial_number,
83440024Sgibbs	      sizeof(adw->serial_number));
83540024Sgibbs	if (checksum != eep_config.checksum) {
83640024Sgibbs		u_int16_t serial_number[3];
83740024Sgibbs
83856979Sgibbs		adw->flags |= ADW_EEPROM_FAILED;
839241588Sjhb		device_printf(adw->device,
840241588Sjhb		    "EEPROM checksum failed.  Restoring Defaults\n");
84140024Sgibbs
84240024Sgibbs	        /*
84340024Sgibbs		 * Restore the default EEPROM settings.
84440024Sgibbs		 * Assume the 6 byte board serial number that was read
84540024Sgibbs		 * from EEPROM is correct even if the EEPROM checksum
84640024Sgibbs		 * failed.
84740024Sgibbs		 */
84856979Sgibbs		bcopy(adw->default_eeprom, &eep_config, sizeof(eep_config));
84940024Sgibbs		bcopy(adw->serial_number, eep_config.serial_number,
85040024Sgibbs		      sizeof(serial_number));
85140024Sgibbs		adw_eeprom_write(adw, &eep_config);
85240024Sgibbs	}
85340024Sgibbs
85440024Sgibbs	/* Pull eeprom information into our softc. */
85540024Sgibbs	adw->bios_ctrl = eep_config.bios_ctrl;
85640024Sgibbs	adw->user_wdtr = eep_config.wdtr_able;
85756979Sgibbs	for (tid = 0; tid < ADW_MAX_TID; tid++) {
85856979Sgibbs		u_int	  mc_sdtr;
85956979Sgibbs		u_int16_t tid_mask;
86056979Sgibbs
86156979Sgibbs		tid_mask = 0x1 << tid;
86256979Sgibbs		if ((adw->features & ADW_ULTRA) != 0) {
86356979Sgibbs			/*
86456979Sgibbs			 * Ultra chips store sdtr and ultraenb
86556979Sgibbs			 * bits in their seeprom, so we must
86656979Sgibbs			 * construct valid mc_sdtr entries for
86756979Sgibbs			 * indirectly.
86856979Sgibbs			 */
86956979Sgibbs			if (eep_config.sync1.sync_enable & tid_mask) {
87056979Sgibbs				if (eep_config.sync2.ultra_enable & tid_mask)
87156979Sgibbs					mc_sdtr = ADW_MC_SDTR_20;
87256979Sgibbs				else
87356979Sgibbs					mc_sdtr = ADW_MC_SDTR_10;
87456979Sgibbs			} else
87556979Sgibbs				mc_sdtr = ADW_MC_SDTR_ASYNC;
87656979Sgibbs		} else {
87756979Sgibbs			switch (ADW_TARGET_GROUP(tid)) {
87856979Sgibbs			case 3:
87956979Sgibbs				mc_sdtr = eep_config.sync4.sdtr4;
88056979Sgibbs				break;
88156979Sgibbs			case 2:
88256979Sgibbs				mc_sdtr = eep_config.sync3.sdtr3;
88356979Sgibbs				break;
88456979Sgibbs			case 1:
88556979Sgibbs				mc_sdtr = eep_config.sync2.sdtr2;
88656979Sgibbs				break;
88756979Sgibbs			default: /* Shut up compiler */
88856979Sgibbs			case 0:
88956979Sgibbs				mc_sdtr = eep_config.sync1.sdtr1;
89056979Sgibbs				break;
89156979Sgibbs			}
89256979Sgibbs			mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid);
89356979Sgibbs			mc_sdtr &= 0xFF;
89456979Sgibbs		}
89556979Sgibbs		adw_set_user_sdtr(adw, tid, mc_sdtr);
89656979Sgibbs	}
89740024Sgibbs	adw->user_tagenb = eep_config.tagqng_able;
89840024Sgibbs	adw->user_discenb = eep_config.disc_enable;
89940024Sgibbs	adw->max_acbs = eep_config.max_host_qng;
90040024Sgibbs	adw->initiator_id = (eep_config.adapter_scsi_id & ADW_MAX_TID);
90140024Sgibbs
90240024Sgibbs	/*
90340024Sgibbs	 * Sanity check the number of host openings.
90440024Sgibbs	 */
90540024Sgibbs	if (adw->max_acbs > ADW_DEF_MAX_HOST_QNG)
90640024Sgibbs		adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
90740024Sgibbs	else if (adw->max_acbs < ADW_DEF_MIN_HOST_QNG) {
90840024Sgibbs        	/* If the value is zero, assume it is uninitialized. */
90940024Sgibbs		if (adw->max_acbs == 0)
91040024Sgibbs			adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
91140024Sgibbs		else
91240024Sgibbs			adw->max_acbs = ADW_DEF_MIN_HOST_QNG;
91340024Sgibbs	}
91440024Sgibbs
91540024Sgibbs	scsicfg1 = 0;
91656979Sgibbs	if ((adw->features & ADW_ULTRA2) != 0) {
91756979Sgibbs		switch (eep_config.termination_lvd) {
91856979Sgibbs		default:
919241588Sjhb			device_printf(adw->device,
920241588Sjhb			    "Invalid EEPROM LVD Termination Settings.\n");
921241588Sjhb			device_printf(adw->device,
922241588Sjhb			    "Reverting to Automatic LVD Termination\n");
92356979Sgibbs			/* FALLTHROUGH */
92456979Sgibbs		case ADW_EEPROM_TERM_AUTO:
92556979Sgibbs			break;
92656979Sgibbs		case ADW_EEPROM_TERM_BOTH_ON:
92756979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_LO;
92856979Sgibbs			/* FALLTHROUGH */
92956979Sgibbs		case ADW_EEPROM_TERM_HIGH_ON:
93056979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_HI;
93156979Sgibbs			/* FALLTHROUGH */
93256979Sgibbs		case ADW_EEPROM_TERM_OFF:
93356979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_DIS_TERM_DRV;
93456979Sgibbs			break;
93556979Sgibbs		}
93656979Sgibbs	}
93756979Sgibbs
93856979Sgibbs	switch (eep_config.termination_se) {
93940024Sgibbs	default:
940241588Sjhb		device_printf(adw->device,
941241588Sjhb		    "Invalid SE EEPROM Termination Settings.\n");
942241588Sjhb		device_printf(adw->device,
943241588Sjhb		    "Reverting to Automatic SE Termination\n");
94440024Sgibbs		/* FALLTHROUGH */
94540024Sgibbs	case ADW_EEPROM_TERM_AUTO:
94640024Sgibbs		break;
94740024Sgibbs	case ADW_EEPROM_TERM_BOTH_ON:
94840024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L;
94940024Sgibbs		/* FALLTHROUGH */
95040024Sgibbs	case ADW_EEPROM_TERM_HIGH_ON:
95140024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H;
95240024Sgibbs		/* FALLTHROUGH */
95340024Sgibbs	case ADW_EEPROM_TERM_OFF:
95440024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL;
95540024Sgibbs		break;
95640024Sgibbs	}
957241588Sjhb	device_printf(adw->device, "SCSI ID %d, ", adw->initiator_id);
95840024Sgibbs
95940024Sgibbs	/* DMA tag for mapping buffers into device visible space. */
960112782Smdodd	if (bus_dma_tag_create(
961112782Smdodd			/* parent	*/ adw->parent_dmat,
962112782Smdodd			/* alignment	*/ 1,
963112782Smdodd			/* boundary	*/ 0,
964112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
965112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
966112782Smdodd			/* filter	*/ NULL,
967112782Smdodd			/* filterarg	*/ NULL,
968281826Smav			/* maxsize	*/ DFLTPHYS,
969112782Smdodd			/* nsegments	*/ ADW_SGSIZE,
970112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
971112782Smdodd			/* flags	*/ BUS_DMA_ALLOCNOW,
972117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
973241588Sjhb			/* lockarg	*/ &adw->lock,
974112782Smdodd			&adw->buffer_dmat) != 0) {
97556979Sgibbs		return (ENOMEM);
97640024Sgibbs	}
97740024Sgibbs
97840024Sgibbs	adw->init_level++;
97940024Sgibbs
98056979Sgibbs	/* DMA tag for our ccb carrier structures */
981112782Smdodd	if (bus_dma_tag_create(
982112782Smdodd			/* parent	*/ adw->parent_dmat,
983112782Smdodd			/* alignment	*/ 0x10,
984112782Smdodd			/* boundary	*/ 0,
985112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
986112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
987112782Smdodd			/* filter	*/ NULL,
988112782Smdodd			/* filterarg	*/ NULL,
989112782Smdodd			/* maxsize	*/ (adw->max_acbs +
990112782Smdodd					    ADW_NUM_CARRIER_QUEUES + 1) *
991112782Smdodd					    sizeof(struct adw_carrier),
992112782Smdodd			/* nsegments	*/ 1,
993112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
994112782Smdodd			/* flags	*/ 0,
995241588Sjhb			/* lockfunc	*/ NULL,
996241588Sjhb			/* lockarg	*/ NULL,
997112782Smdodd			&adw->carrier_dmat) != 0) {
99856979Sgibbs		return (ENOMEM);
99956979Sgibbs        }
100056979Sgibbs
100156979Sgibbs	adw->init_level++;
100256979Sgibbs
100356979Sgibbs	/* Allocation for our ccb carrier structures */
100456979Sgibbs	if (bus_dmamem_alloc(adw->carrier_dmat, (void **)&adw->carriers,
100556979Sgibbs			     BUS_DMA_NOWAIT, &adw->carrier_dmamap) != 0) {
100656979Sgibbs		return (ENOMEM);
100756979Sgibbs	}
100856979Sgibbs
100956979Sgibbs	adw->init_level++;
101056979Sgibbs
101156979Sgibbs	/* And permanently map them */
101256979Sgibbs	bus_dmamap_load(adw->carrier_dmat, adw->carrier_dmamap,
101356979Sgibbs			adw->carriers,
101456979Sgibbs			(adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
101556979Sgibbs			 * sizeof(struct adw_carrier),
101656979Sgibbs			adwmapmem, &adw->carrier_busbase, /*flags*/0);
101756979Sgibbs
101856979Sgibbs	/* Clear them out. */
101956979Sgibbs	bzero(adw->carriers, (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
102056979Sgibbs			     * sizeof(struct adw_carrier));
102156979Sgibbs
102256979Sgibbs	/* Setup our free carrier list */
102356979Sgibbs	adw->free_carriers = adw->carriers;
102456979Sgibbs	for (i = 0; i < adw->max_acbs + ADW_NUM_CARRIER_QUEUES; i++) {
102556979Sgibbs		adw->carriers[i].carr_offset =
102656979Sgibbs			carriervtobo(adw, &adw->carriers[i]);
102756979Sgibbs		adw->carriers[i].carr_ba =
102856979Sgibbs			carriervtob(adw, &adw->carriers[i]);
102956979Sgibbs		adw->carriers[i].areq_ba = 0;
103056979Sgibbs		adw->carriers[i].next_ba =
103156979Sgibbs			carriervtobo(adw, &adw->carriers[i+1]);
103256979Sgibbs	}
103356979Sgibbs	/* Terminal carrier.  Never leaves the freelist */
103456979Sgibbs	adw->carriers[i].carr_offset =
103556979Sgibbs		carriervtobo(adw, &adw->carriers[i]);
103656979Sgibbs	adw->carriers[i].carr_ba =
103756979Sgibbs		carriervtob(adw, &adw->carriers[i]);
103856979Sgibbs	adw->carriers[i].areq_ba = 0;
103956979Sgibbs	adw->carriers[i].next_ba = ~0;
104056979Sgibbs
104156979Sgibbs	adw->init_level++;
104256979Sgibbs
104356979Sgibbs	/* DMA tag for our acb structures */
1044112782Smdodd	if (bus_dma_tag_create(
1045112782Smdodd			/* parent	*/ adw->parent_dmat,
1046112782Smdodd			/* alignment	*/ 1,
1047112782Smdodd			/* boundary	*/ 0,
1048112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1049112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1050112782Smdodd			/* filter	*/ NULL,
1051112782Smdodd			/* filterarg	*/ NULL,
1052112782Smdodd			/* maxsize	*/ adw->max_acbs * sizeof(struct acb),
1053112782Smdodd			/* nsegments	*/ 1,
1054112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1055112782Smdodd			/* flags	*/ 0,
1056241588Sjhb			/* lockfunc	*/ NULL,
1057241588Sjhb			/* lockarg	*/ NULL,
1058112782Smdodd			&adw->acb_dmat) != 0) {
105956979Sgibbs		return (ENOMEM);
106040024Sgibbs        }
106140024Sgibbs
106240024Sgibbs	adw->init_level++;
106340024Sgibbs
106440024Sgibbs	/* Allocation for our ccbs */
106540024Sgibbs	if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs,
106656979Sgibbs			     BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0)
106756979Sgibbs		return (ENOMEM);
106840024Sgibbs
106940024Sgibbs	adw->init_level++;
107040024Sgibbs
107140024Sgibbs	/* And permanently map them */
107240024Sgibbs	bus_dmamap_load(adw->acb_dmat, adw->acb_dmamap,
107340024Sgibbs			adw->acbs,
107440024Sgibbs			adw->max_acbs * sizeof(struct acb),
107540024Sgibbs			adwmapmem, &adw->acb_busbase, /*flags*/0);
107640024Sgibbs
107740024Sgibbs	/* Clear them out. */
107840024Sgibbs	bzero(adw->acbs, adw->max_acbs * sizeof(struct acb));
107940024Sgibbs
108040024Sgibbs	/* DMA tag for our S/G structures.  We allocate in page sized chunks */
1081112782Smdodd	if (bus_dma_tag_create(
1082112782Smdodd			/* parent	*/ adw->parent_dmat,
1083112782Smdodd			/* alignment	*/ 1,
1084112782Smdodd			/* boundary	*/ 0,
1085112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1086112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1087112782Smdodd			/* filter	*/ NULL,
1088112782Smdodd			/* filterarg	*/ NULL,
1089112782Smdodd			/* maxsize	*/ PAGE_SIZE,
1090112782Smdodd			/* nsegments	*/ 1,
1091112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1092112782Smdodd			/* flags	*/ 0,
1093241588Sjhb			/* lockfunc	*/ NULL,
1094241588Sjhb			/* lockarg	*/ NULL,
1095112782Smdodd			&adw->sg_dmat) != 0) {
109656979Sgibbs		return (ENOMEM);
109740024Sgibbs        }
109840024Sgibbs
109940024Sgibbs	adw->init_level++;
110040024Sgibbs
110140024Sgibbs	/* Allocate our first batch of ccbs */
1102241588Sjhb	mtx_lock(&adw->lock);
1103241588Sjhb	if (adwallocacbs(adw) == 0) {
1104241588Sjhb		mtx_unlock(&adw->lock);
110556979Sgibbs		return (ENOMEM);
1106241588Sjhb	}
110740024Sgibbs
1108241588Sjhb	if (adw_init_chip(adw, scsicfg1) != 0) {
1109241588Sjhb		mtx_unlock(&adw->lock);
111056979Sgibbs		return (ENXIO);
1111241588Sjhb	}
111256979Sgibbs
111356979Sgibbs	printf("Queue Depth %d\n", adw->max_acbs);
1114241588Sjhb	mtx_unlock(&adw->lock);
111556979Sgibbs
111640024Sgibbs	return (0);
111740024Sgibbs}
111840024Sgibbs
111940024Sgibbs/*
112040024Sgibbs * Attach all the sub-devices we can find
112140024Sgibbs */
112240024Sgibbsint
112340024Sgibbsadw_attach(struct adw_softc *adw)
112440024Sgibbs{
112540024Sgibbs	struct ccb_setasync csa;
112640024Sgibbs	struct cam_devq *devq;
112756979Sgibbs	int error;
112840024Sgibbs
112956979Sgibbs	/* Hook up our interrupt handler */
1130241588Sjhb	error = bus_setup_intr(adw->device, adw->irq,
1131241588Sjhb	    INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE, NULL, adw_intr, adw,
1132241588Sjhb	    &adw->ih);
1133241588Sjhb	if (error != 0) {
113456979Sgibbs		device_printf(adw->device, "bus_setup_intr() failed: %d\n",
113556979Sgibbs			      error);
1136241588Sjhb		return (error);
113756979Sgibbs	}
113856979Sgibbs
113940024Sgibbs	/* Start the Risc processor now that we are fully configured. */
114040024Sgibbs	adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN);
114140024Sgibbs
114240024Sgibbs	/*
114340024Sgibbs	 * Create the device queue for our SIM.
114440024Sgibbs	 */
114540024Sgibbs	devq = cam_simq_alloc(adw->max_acbs);
114640024Sgibbs	if (devq == NULL)
114756979Sgibbs		return (ENOMEM);
114840024Sgibbs
114940024Sgibbs	/*
115040024Sgibbs	 * Construct our SIM entry.
115140024Sgibbs	 */
1152241588Sjhb	adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw,
1153241588Sjhb	    device_get_unit(adw->device), &adw->lock, 1, adw->max_acbs, devq);
1154241588Sjhb	if (adw->sim == NULL)
1155241588Sjhb		return (ENOMEM);
115640024Sgibbs
115740024Sgibbs	/*
115840024Sgibbs	 * Register the bus.
115940024Sgibbs	 */
1160241588Sjhb	mtx_lock(&adw->lock);
1161170872Sscottl	if (xpt_bus_register(adw->sim, adw->device, 0) != CAM_SUCCESS) {
116240024Sgibbs		cam_sim_free(adw->sim, /*free devq*/TRUE);
116356979Sgibbs		error = ENOMEM;
116456979Sgibbs		goto fail;
116540024Sgibbs	}
116640024Sgibbs
116740024Sgibbs	if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim),
116840024Sgibbs			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
116940024Sgibbs	   == CAM_REQ_CMP) {
117040024Sgibbs		xpt_setup_ccb(&csa.ccb_h, adw->path, /*priority*/5);
117140024Sgibbs		csa.ccb_h.func_code = XPT_SASYNC_CB;
117240024Sgibbs		csa.event_enable = AC_LOST_DEVICE;
117340024Sgibbs		csa.callback = adw_async;
117440024Sgibbs		csa.callback_arg = adw;
117540024Sgibbs		xpt_action((union ccb *)&csa);
117640024Sgibbs	}
117740024Sgibbs
117856979Sgibbsfail:
1179241588Sjhb	mtx_unlock(&adw->lock);
118056979Sgibbs	return (error);
118140024Sgibbs}
118240024Sgibbs
118340024Sgibbsvoid
118440024Sgibbsadw_intr(void *arg)
118540024Sgibbs{
118640024Sgibbs	struct	adw_softc *adw;
1187241588Sjhb
1188241588Sjhb	adw = arg;
1189241588Sjhb	mtx_lock(&adw->lock);
1190241588Sjhb	adw_intr_locked(adw);
1191241588Sjhb	mtx_unlock(&adw->lock);
1192241588Sjhb}
1193241588Sjhb
1194241588Sjhbvoid
1195241588Sjhbadw_intr_locked(struct adw_softc *adw)
1196241588Sjhb{
119740024Sgibbs	u_int	int_stat;
119840024Sgibbs
119940024Sgibbs	if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0)
120040024Sgibbs		return;
120140024Sgibbs
120240024Sgibbs	/* Reading the register clears the interrupt. */
120340024Sgibbs	int_stat = adw_inb(adw, ADW_INTR_STATUS_REG);
120440024Sgibbs
120540024Sgibbs	if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) {
120656979Sgibbs		u_int intrb_code;
120756979Sgibbs
120856979Sgibbs		/* Async Microcode Event */
120956979Sgibbs		intrb_code = adw_lram_read_8(adw, ADW_MC_INTRB_CODE);
121056979Sgibbs		switch (intrb_code) {
121156979Sgibbs		case ADW_ASYNC_CARRIER_READY_FAILURE:
121256979Sgibbs			/*
121356979Sgibbs			 * The RISC missed our update of
121456979Sgibbs			 * the commandq.
121556979Sgibbs			 */
121656979Sgibbs			if (LIST_FIRST(&adw->pending_ccbs) != NULL)
121756979Sgibbs				adw_tickle_risc(adw, ADW_TICKLE_A);
121840024Sgibbs			break;
121956979Sgibbs    		case ADW_ASYNC_SCSI_BUS_RESET_DET:
122056979Sgibbs			/*
122156979Sgibbs			 * The firmware detected a SCSI Bus reset.
122256979Sgibbs			 */
1223241588Sjhb			device_printf(adw->device, "Someone Reset the Bus\n");
122456979Sgibbs			adw_handle_bus_reset(adw, /*initiated*/FALSE);
122556979Sgibbs			break;
122656979Sgibbs		case ADW_ASYNC_RDMA_FAILURE:
122756979Sgibbs			/*
122856979Sgibbs			 * Handle RDMA failure by resetting the
122956979Sgibbs			 * SCSI Bus and chip.
123056979Sgibbs			 */
1231153072Sru#if 0 /* XXX */
123256979Sgibbs			AdvResetChipAndSB(adv_dvc_varp);
123356979Sgibbs#endif
123456979Sgibbs			break;
123556979Sgibbs
123656979Sgibbs		case ADW_ASYNC_HOST_SCSI_BUS_RESET:
123756979Sgibbs			/*
123856979Sgibbs			 * Host generated SCSI bus reset occurred.
123956979Sgibbs			 */
124040024Sgibbs			adw_handle_bus_reset(adw, /*initiated*/TRUE);
124156979Sgibbs        		break;
124256979Sgibbs    		default:
124356979Sgibbs			printf("adw_intr: unknown async code 0x%x\n",
124456979Sgibbs			       intrb_code);
124540024Sgibbs			break;
124640024Sgibbs		}
124740024Sgibbs	}
124840024Sgibbs
124940024Sgibbs	/*
125056979Sgibbs	 * Run down the RequestQ.
125140024Sgibbs	 */
125256979Sgibbs	while ((adw->responseq->next_ba & ADW_RQ_DONE) != 0) {
125356979Sgibbs		struct adw_carrier *free_carrier;
125456979Sgibbs		struct acb *acb;
125556979Sgibbs		union ccb *ccb;
125640024Sgibbs
125756979Sgibbs#if 0
125856979Sgibbs		printf("0x%x, 0x%x, 0x%x, 0x%x\n",
125956979Sgibbs		       adw->responseq->carr_offset,
126056979Sgibbs		       adw->responseq->carr_ba,
126156979Sgibbs		       adw->responseq->areq_ba,
126256979Sgibbs		       adw->responseq->next_ba);
126356979Sgibbs#endif
126456979Sgibbs		/*
126556979Sgibbs		 * The firmware copies the adw_scsi_req_q.acb_baddr
126656979Sgibbs		 * field into the areq_ba field of the carrier.
126756979Sgibbs		 */
126856979Sgibbs		acb = acbbotov(adw, adw->responseq->areq_ba);
126940024Sgibbs
127040024Sgibbs		/*
127156979Sgibbs		 * The least significant four bits of the next_ba
127256979Sgibbs		 * field are used as flags.  Mask them out and then
127356979Sgibbs		 * advance through the list.
127440024Sgibbs		 */
127556979Sgibbs		free_carrier = adw->responseq;
127656979Sgibbs		adw->responseq =
127756979Sgibbs		    carrierbotov(adw, free_carrier->next_ba & ADW_NEXT_BA_MASK);
127856979Sgibbs		free_carrier->next_ba = adw->free_carriers->carr_offset;
127956979Sgibbs		adw->free_carriers = free_carrier;
128040024Sgibbs
128140024Sgibbs		/* Process CCB */
128240024Sgibbs		ccb = acb->ccb;
1283241588Sjhb		callout_stop(&acb->timer);
128440024Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
1285115343Sscottl			bus_dmasync_op_t op;
128640024Sgibbs
128740024Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
128840024Sgibbs				op = BUS_DMASYNC_POSTREAD;
128940024Sgibbs			else
129040024Sgibbs				op = BUS_DMASYNC_POSTWRITE;
129140024Sgibbs			bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
129240024Sgibbs			bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
129340024Sgibbs			ccb->csio.resid = acb->queue.data_cnt;
129440024Sgibbs		} else
129540024Sgibbs			ccb->csio.resid = 0;
129640024Sgibbs
129740024Sgibbs		/* Common Cases inline... */
129840024Sgibbs		if (acb->queue.host_status == QHSTA_NO_ERROR
129940024Sgibbs		 && (acb->queue.done_status == QD_NO_ERROR
130040024Sgibbs		  || acb->queue.done_status == QD_WITH_ERROR)) {
130140024Sgibbs			ccb->csio.scsi_status = acb->queue.scsi_status;
130240024Sgibbs			ccb->ccb_h.status = 0;
130340024Sgibbs			switch (ccb->csio.scsi_status) {
130440024Sgibbs			case SCSI_STATUS_OK:
130540024Sgibbs				ccb->ccb_h.status |= CAM_REQ_CMP;
130640024Sgibbs				break;
130740024Sgibbs			case SCSI_STATUS_CHECK_COND:
130840024Sgibbs			case SCSI_STATUS_CMD_TERMINATED:
130940024Sgibbs				bcopy(&acb->sense_data, &ccb->csio.sense_data,
131040024Sgibbs				      ccb->csio.sense_len);
131140024Sgibbs				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
131240024Sgibbs				ccb->csio.sense_resid = acb->queue.sense_len;
131340024Sgibbs				/* FALLTHROUGH */
131440024Sgibbs			default:
131540024Sgibbs				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR
131640024Sgibbs						  |  CAM_DEV_QFRZN;
131740024Sgibbs				xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
131840024Sgibbs				break;
131940024Sgibbs			}
132040024Sgibbs			adwfreeacb(adw, acb);
132140024Sgibbs			xpt_done(ccb);
132240024Sgibbs		} else {
132340024Sgibbs			adwprocesserror(adw, acb);
132440024Sgibbs		}
132540024Sgibbs	}
132640024Sgibbs}
132740024Sgibbs
132840024Sgibbsstatic void
132940024Sgibbsadwprocesserror(struct adw_softc *adw, struct acb *acb)
133040024Sgibbs{
133140024Sgibbs	union ccb *ccb;
133240024Sgibbs
133340024Sgibbs	ccb = acb->ccb;
133440024Sgibbs	if (acb->queue.done_status == QD_ABORTED_BY_HOST) {
133540024Sgibbs		ccb->ccb_h.status = CAM_REQ_ABORTED;
133640024Sgibbs	} else {
133740024Sgibbs
133840024Sgibbs		switch (acb->queue.host_status) {
133940024Sgibbs		case QHSTA_M_SEL_TIMEOUT:
134040024Sgibbs			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
134140024Sgibbs			break;
134240024Sgibbs		case QHSTA_M_SXFR_OFF_UFLW:
134340024Sgibbs		case QHSTA_M_SXFR_OFF_OFLW:
134440024Sgibbs		case QHSTA_M_DATA_OVER_RUN:
134540024Sgibbs			ccb->ccb_h.status = CAM_DATA_RUN_ERR;
134640024Sgibbs			break;
134740024Sgibbs		case QHSTA_M_SXFR_DESELECTED:
134840024Sgibbs		case QHSTA_M_UNEXPECTED_BUS_FREE:
134940024Sgibbs			ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
135040024Sgibbs			break;
135157679Sgibbs		case QHSTA_M_SCSI_BUS_RESET:
135257679Sgibbs		case QHSTA_M_SCSI_BUS_RESET_UNSOL:
135357679Sgibbs			ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
135457679Sgibbs			break;
135557679Sgibbs		case QHSTA_M_BUS_DEVICE_RESET:
135657679Sgibbs			ccb->ccb_h.status = CAM_BDR_SENT;
135757679Sgibbs			break;
135840024Sgibbs		case QHSTA_M_QUEUE_ABORTED:
135940024Sgibbs			/* BDR or Bus Reset */
1360241588Sjhb			xpt_print_path(adw->path);
136157679Sgibbs			printf("Saw Queue Aborted\n");
136240024Sgibbs			ccb->ccb_h.status = adw->last_reset;
136340024Sgibbs			break;
136440024Sgibbs		case QHSTA_M_SXFR_SDMA_ERR:
136540024Sgibbs		case QHSTA_M_SXFR_SXFR_PERR:
136640024Sgibbs		case QHSTA_M_RDMA_PERR:
136740024Sgibbs			ccb->ccb_h.status = CAM_UNCOR_PARITY;
136840024Sgibbs			break;
136940024Sgibbs		case QHSTA_M_WTM_TIMEOUT:
137040024Sgibbs		case QHSTA_M_SXFR_WD_TMO:
137156979Sgibbs		{
137240024Sgibbs			/* The SCSI bus hung in a phase */
137357679Sgibbs			xpt_print_path(adw->path);
1374241588Sjhb			printf("Watch Dog timer expired.  Resetting bus\n");
137557679Sgibbs			adw_reset_bus(adw);
137640024Sgibbs			break;
137756979Sgibbs		}
137840024Sgibbs		case QHSTA_M_SXFR_XFR_PH_ERR:
137940024Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
138040024Sgibbs			break;
138140024Sgibbs		case QHSTA_M_SXFR_UNKNOWN_ERROR:
138240024Sgibbs			break;
138340024Sgibbs		case QHSTA_M_BAD_CMPL_STATUS_IN:
138440024Sgibbs			/* No command complete after a status message */
138540024Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
138640024Sgibbs			break;
138740024Sgibbs		case QHSTA_M_AUTO_REQ_SENSE_FAIL:
138840024Sgibbs			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
138940024Sgibbs			break;
139040024Sgibbs		case QHSTA_M_INVALID_DEVICE:
139140024Sgibbs			ccb->ccb_h.status = CAM_PATH_INVALID;
139240024Sgibbs			break;
139340024Sgibbs		case QHSTA_M_NO_AUTO_REQ_SENSE:
139440024Sgibbs			/*
139540024Sgibbs			 * User didn't request sense, but we got a
139640024Sgibbs			 * check condition.
139740024Sgibbs			 */
139840024Sgibbs			ccb->csio.scsi_status = acb->queue.scsi_status;
139940024Sgibbs			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
140040024Sgibbs			break;
140140024Sgibbs		default:
140240024Sgibbs			panic("%s: Unhandled Host status error %x",
1403241588Sjhb			    device_get_nameunit(adw->device),
1404241588Sjhb			    acb->queue.host_status);
140540024Sgibbs			/* NOTREACHED */
140640024Sgibbs		}
140740024Sgibbs	}
140857679Sgibbs	if ((acb->state & ACB_RECOVERY_ACB) != 0) {
140957679Sgibbs		if (ccb->ccb_h.status == CAM_SCSI_BUS_RESET
141057679Sgibbs		 || ccb->ccb_h.status == CAM_BDR_SENT)
141157679Sgibbs		 	ccb->ccb_h.status = CAM_CMD_TIMEOUT;
141257679Sgibbs	}
141340024Sgibbs	if (ccb->ccb_h.status != CAM_REQ_CMP) {
141440024Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
141540024Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
141640024Sgibbs	}
141740024Sgibbs	adwfreeacb(adw, acb);
141840024Sgibbs	xpt_done(ccb);
141940024Sgibbs}
142040024Sgibbs
142140024Sgibbsstatic void
142240024Sgibbsadwtimeout(void *arg)
142340024Sgibbs{
142440024Sgibbs	struct acb	     *acb;
142540024Sgibbs	union  ccb	     *ccb;
142640024Sgibbs	struct adw_softc     *adw;
142740024Sgibbs	adw_idle_cmd_status_t status;
142857679Sgibbs	int		      target_id;
142940024Sgibbs
143040024Sgibbs	acb = (struct acb *)arg;
143140024Sgibbs	ccb = acb->ccb;
143240024Sgibbs	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
143340024Sgibbs	xpt_print_path(ccb->ccb_h.path);
143440024Sgibbs	printf("ACB %p - timed out\n", (void *)acb);
143540024Sgibbs
1436241588Sjhb	mtx_assert(&adw->lock, MA_OWNED);
143740024Sgibbs
143840024Sgibbs	if ((acb->state & ACB_ACTIVE) == 0) {
143940024Sgibbs		xpt_print_path(ccb->ccb_h.path);
144040024Sgibbs		printf("ACB %p - timed out CCB already completed\n",
144140024Sgibbs		       (void *)acb);
144240024Sgibbs		return;
144340024Sgibbs	}
144440024Sgibbs
144557679Sgibbs	acb->state |= ACB_RECOVERY_ACB;
144657679Sgibbs	target_id = ccb->ccb_h.target_id;
144757679Sgibbs
144840024Sgibbs	/* Attempt a BDR first */
144957679Sgibbs	status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
145057679Sgibbs				   ccb->ccb_h.target_id);
145140024Sgibbs	if (status == ADW_IDLE_CMD_SUCCESS) {
1452241588Sjhb		device_printf(adw->device,
1453241588Sjhb		    "BDR Delivered.  No longer in timeout\n");
145457679Sgibbs		adw_handle_device_reset(adw, target_id);
145540024Sgibbs	} else {
145657679Sgibbs		adw_reset_bus(adw);
145757679Sgibbs		xpt_print_path(adw->path);
145857679Sgibbs		printf("Bus Reset Delivered.  No longer in timeout\n");
145940024Sgibbs	}
146040024Sgibbs}
146140024Sgibbs
146240024Sgibbsstatic void
146340024Sgibbsadw_handle_device_reset(struct adw_softc *adw, u_int target)
146440024Sgibbs{
146540024Sgibbs	struct cam_path *path;
146640024Sgibbs	cam_status error;
146740024Sgibbs
146840024Sgibbs	error = xpt_create_path(&path, /*periph*/NULL, cam_sim_path(adw->sim),
146940024Sgibbs				target, CAM_LUN_WILDCARD);
147040024Sgibbs
147140024Sgibbs	if (error == CAM_REQ_CMP) {
147240024Sgibbs		xpt_async(AC_SENT_BDR, path, NULL);
147340024Sgibbs		xpt_free_path(path);
147440024Sgibbs	}
147540024Sgibbs	adw->last_reset = CAM_BDR_SENT;
147640024Sgibbs}
147740024Sgibbs
147840024Sgibbsstatic void
147940024Sgibbsadw_handle_bus_reset(struct adw_softc *adw, int initiated)
148040024Sgibbs{
148140024Sgibbs	if (initiated) {
148240024Sgibbs		/*
148340024Sgibbs		 * The microcode currently sets the SCSI Bus Reset signal
148440024Sgibbs		 * while handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET
148540024Sgibbs		 * command above.  But the SCSI Bus Reset Hold Time in the
148640024Sgibbs		 * microcode is not deterministic (it may in fact be for less
148740024Sgibbs		 * than the SCSI Spec. minimum of 25 us).  Therefore on return
148840024Sgibbs		 * the Adv Library sets the SCSI Bus Reset signal for
148940024Sgibbs		 * ADW_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
149040024Sgibbs		 * than 25 us.
149140024Sgibbs		 */
149240024Sgibbs		u_int scsi_ctrl;
149340024Sgibbs
149440024Sgibbs	    	scsi_ctrl = adw_inw(adw, ADW_SCSI_CTRL) & ~ADW_SCSI_CTRL_RSTOUT;
149540024Sgibbs		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl | ADW_SCSI_CTRL_RSTOUT);
149640024Sgibbs		DELAY(ADW_SCSI_RESET_HOLD_TIME_US);
149740024Sgibbs		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl);
149840024Sgibbs
149940024Sgibbs		/*
150040024Sgibbs		 * We will perform the async notification when the
150140024Sgibbs		 * SCSI Reset interrupt occurs.
150240024Sgibbs		 */
150340024Sgibbs	} else
150440024Sgibbs		xpt_async(AC_BUS_RESET, adw->path, NULL);
150540024Sgibbs	adw->last_reset = CAM_SCSI_BUS_RESET;
150640024Sgibbs}
1507165102SmjacobMODULE_DEPEND(adw, cam, 1, 1, 1);
1508165102Smjacob
1509