adwcam.c revision 163816
1139749Simp/*-
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 163816 2006-10-31 05:53:29Z mjacob $");
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.h>
5856979Sgibbs#include <machine/resource.h>
5940024Sgibbs
6056979Sgibbs#include <sys/rman.h>
6156979Sgibbs
6240024Sgibbs#include <cam/cam.h>
6340024Sgibbs#include <cam/cam_ccb.h>
6440024Sgibbs#include <cam/cam_sim.h>
6540024Sgibbs#include <cam/cam_xpt_sim.h>
6640024Sgibbs#include <cam/cam_debug.h>
6740024Sgibbs
6840024Sgibbs#include <cam/scsi/scsi_message.h>
6940024Sgibbs
7040024Sgibbs#include <dev/advansys/adwvar.h>
7140024Sgibbs
7240024Sgibbs/* Definitions for our use of the SIM private CCB area */
7340024Sgibbs#define ccb_acb_ptr spriv_ptr0
7440024Sgibbs#define ccb_adw_ptr spriv_ptr1
7540024Sgibbs
7640024Sgibbsu_long adw_unit;
7740024Sgibbs
7857679Sgibbsstatic __inline cam_status	adwccbstatus(union ccb*);
7940024Sgibbsstatic __inline struct acb*	adwgetacb(struct adw_softc *adw);
8040024Sgibbsstatic __inline void		adwfreeacb(struct adw_softc *adw,
8140024Sgibbs					   struct acb *acb);
8240024Sgibbs
8340024Sgibbsstatic void		adwmapmem(void *arg, bus_dma_segment_t *segs,
8440024Sgibbs				  int nseg, int error);
8540024Sgibbsstatic struct sg_map_node*
8640024Sgibbs			adwallocsgmap(struct adw_softc *adw);
8740024Sgibbsstatic int		adwallocacbs(struct adw_softc *adw);
8840024Sgibbs
8940024Sgibbsstatic void		adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs,
9040024Sgibbs				      int nseg, int error);
9140024Sgibbsstatic void		adw_action(struct cam_sim *sim, union ccb *ccb);
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
10257679Sgibbsstatic __inline cam_status
10357679Sgibbsadwccbstatus(union ccb* ccb)
10457679Sgibbs{
10557679Sgibbs	return (ccb->ccb_h.status & CAM_STATUS_MASK);
10657679Sgibbs}
10757679Sgibbs
10840024Sgibbsstatic __inline struct acb*
10940024Sgibbsadwgetacb(struct adw_softc *adw)
11040024Sgibbs{
11140024Sgibbs	struct	acb* acb;
11240024Sgibbs	int	s;
11340024Sgibbs
11440024Sgibbs	s = splcam();
11540024Sgibbs	if ((acb = SLIST_FIRST(&adw->free_acb_list)) != NULL) {
11640024Sgibbs		SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
11740024Sgibbs	} else if (adw->num_acbs < adw->max_acbs) {
11840024Sgibbs		adwallocacbs(adw);
11940024Sgibbs		acb = SLIST_FIRST(&adw->free_acb_list);
12040024Sgibbs		if (acb == NULL)
12140024Sgibbs			printf("%s: Can't malloc ACB\n", adw_name(adw));
12240024Sgibbs		else {
12340024Sgibbs			SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
12440024Sgibbs		}
12540024Sgibbs	}
12640024Sgibbs	splx(s);
12740024Sgibbs
12840024Sgibbs	return (acb);
12940024Sgibbs}
13040024Sgibbs
13140024Sgibbsstatic __inline void
13240024Sgibbsadwfreeacb(struct adw_softc *adw, struct acb *acb)
13340024Sgibbs{
13440024Sgibbs	int s;
13540024Sgibbs
13640024Sgibbs	s = splcam();
13740024Sgibbs	if ((acb->state & ACB_ACTIVE) != 0)
13840024Sgibbs		LIST_REMOVE(&acb->ccb->ccb_h, sim_links.le);
13940024Sgibbs	if ((acb->state & ACB_RELEASE_SIMQ) != 0)
14040024Sgibbs		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
14140024Sgibbs	else if ((adw->state & ADW_RESOURCE_SHORTAGE) != 0
14240024Sgibbs	      && (acb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
14340024Sgibbs		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
14440024Sgibbs		adw->state &= ~ADW_RESOURCE_SHORTAGE;
14540024Sgibbs	}
14640024Sgibbs	acb->state = ACB_FREE;
14740024Sgibbs	SLIST_INSERT_HEAD(&adw->free_acb_list, acb, links);
14840024Sgibbs	splx(s);
14940024Sgibbs}
15040024Sgibbs
15140024Sgibbsstatic void
15240024Sgibbsadwmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
15340024Sgibbs{
15440024Sgibbs	bus_addr_t *busaddrp;
15540024Sgibbs
15640024Sgibbs	busaddrp = (bus_addr_t *)arg;
15740024Sgibbs	*busaddrp = segs->ds_addr;
15840024Sgibbs}
15940024Sgibbs
16040024Sgibbsstatic struct sg_map_node *
16140024Sgibbsadwallocsgmap(struct adw_softc *adw)
16240024Sgibbs{
16340024Sgibbs	struct sg_map_node *sg_map;
16440024Sgibbs
16540024Sgibbs	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
16640024Sgibbs
16740024Sgibbs	if (sg_map == NULL)
16840024Sgibbs		return (NULL);
16940024Sgibbs
17040024Sgibbs	/* Allocate S/G space for the next batch of ACBS */
17140024Sgibbs	if (bus_dmamem_alloc(adw->sg_dmat, (void **)&sg_map->sg_vaddr,
17240024Sgibbs			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
17340024Sgibbs		free(sg_map, M_DEVBUF);
17440024Sgibbs		return (NULL);
17540024Sgibbs	}
17640024Sgibbs
17740024Sgibbs	SLIST_INSERT_HEAD(&adw->sg_maps, sg_map, links);
17840024Sgibbs
17940024Sgibbs	bus_dmamap_load(adw->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
18040024Sgibbs			PAGE_SIZE, adwmapmem, &sg_map->sg_physaddr, /*flags*/0);
18140024Sgibbs
18240024Sgibbs	bzero(sg_map->sg_vaddr, PAGE_SIZE);
18340024Sgibbs	return (sg_map);
18440024Sgibbs}
18540024Sgibbs
18640024Sgibbs/*
18740024Sgibbs * Allocate another chunk of CCB's. Return count of entries added.
18840024Sgibbs * Assumed to be called at splcam().
18940024Sgibbs */
19040024Sgibbsstatic int
19140024Sgibbsadwallocacbs(struct adw_softc *adw)
19240024Sgibbs{
19340024Sgibbs	struct acb *next_acb;
19440024Sgibbs	struct sg_map_node *sg_map;
19540024Sgibbs	bus_addr_t busaddr;
19640024Sgibbs	struct adw_sg_block *blocks;
19740024Sgibbs	int newcount;
19840024Sgibbs	int i;
19940024Sgibbs
20040024Sgibbs	next_acb = &adw->acbs[adw->num_acbs];
20140024Sgibbs	sg_map = adwallocsgmap(adw);
20240024Sgibbs
20340024Sgibbs	if (sg_map == NULL)
20440024Sgibbs		return (0);
20540024Sgibbs
20640024Sgibbs	blocks = sg_map->sg_vaddr;
20740024Sgibbs	busaddr = sg_map->sg_physaddr;
20840024Sgibbs
20940024Sgibbs	newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks)));
21040024Sgibbs	for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) {
21140024Sgibbs		int error;
21240024Sgibbs
21340024Sgibbs		error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0,
21440024Sgibbs					  &next_acb->dmamap);
21540024Sgibbs		if (error != 0)
21640024Sgibbs			break;
21756979Sgibbs		next_acb->queue.scsi_req_baddr = acbvtob(adw, next_acb);
21856979Sgibbs		next_acb->queue.scsi_req_bo = acbvtobo(adw, next_acb);
21956979Sgibbs		next_acb->queue.sense_baddr =
22056979Sgibbs		    acbvtob(adw, next_acb) + offsetof(struct acb, sense_data);
22140024Sgibbs		next_acb->sg_blocks = blocks;
22240024Sgibbs		next_acb->sg_busaddr = busaddr;
22340024Sgibbs		next_acb->state = ACB_FREE;
22440024Sgibbs		SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links);
22540024Sgibbs		blocks += ADW_SG_BLOCKCNT;
22640024Sgibbs		busaddr += ADW_SG_BLOCKCNT * sizeof(*blocks);
22740024Sgibbs		next_acb++;
22840024Sgibbs		adw->num_acbs++;
22940024Sgibbs	}
23040024Sgibbs	return (i);
23140024Sgibbs}
23240024Sgibbs
23340024Sgibbsstatic void
23440024Sgibbsadwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
23540024Sgibbs{
23640024Sgibbs	struct	 acb *acb;
23740024Sgibbs	union	 ccb *ccb;
23840024Sgibbs	struct	 adw_softc *adw;
23940420Sgibbs	int	 s;
24040024Sgibbs
24140024Sgibbs	acb = (struct acb *)arg;
24240024Sgibbs	ccb = acb->ccb;
24340024Sgibbs	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
24440024Sgibbs
24540024Sgibbs	if (error != 0) {
24640024Sgibbs		if (error != EFBIG)
24740024Sgibbs			printf("%s: Unexepected error 0x%x returned from "
24840024Sgibbs			       "bus_dmamap_load\n", adw_name(adw), error);
24940024Sgibbs		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
25040024Sgibbs			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
25140024Sgibbs			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
25240024Sgibbs		}
25340024Sgibbs		adwfreeacb(adw, acb);
25440024Sgibbs		xpt_done(ccb);
25540024Sgibbs		return;
25640024Sgibbs	}
25740024Sgibbs
25840024Sgibbs	if (nseg != 0) {
259115343Sscottl		bus_dmasync_op_t op;
26040024Sgibbs
26140024Sgibbs		acb->queue.data_addr = dm_segs[0].ds_addr;
26240024Sgibbs		acb->queue.data_cnt = ccb->csio.dxfer_len;
26340024Sgibbs		if (nseg > 1) {
26440024Sgibbs			struct adw_sg_block *sg_block;
26540024Sgibbs			struct adw_sg_elm *sg;
26640024Sgibbs			bus_addr_t sg_busaddr;
26740024Sgibbs			u_int sg_index;
26840024Sgibbs			bus_dma_segment_t *end_seg;
26940024Sgibbs
27040024Sgibbs			end_seg = dm_segs + nseg;
27140024Sgibbs
27240024Sgibbs			sg_busaddr = acb->sg_busaddr;
27340024Sgibbs			sg_index = 0;
27440024Sgibbs			/* Copy the segments into our SG list */
27540024Sgibbs			for (sg_block = acb->sg_blocks;; sg_block++) {
27656979Sgibbs				u_int i;
27740024Sgibbs
27840024Sgibbs				sg = sg_block->sg_list;
27956979Sgibbs				for (i = 0; i < ADW_NO_OF_SG_PER_BLOCK; i++) {
28056979Sgibbs					if (dm_segs >= end_seg)
28156979Sgibbs						break;
28256979Sgibbs
28340024Sgibbs					sg->sg_addr = dm_segs->ds_addr;
28440024Sgibbs					sg->sg_count = dm_segs->ds_len;
28540024Sgibbs					sg++;
28640024Sgibbs					dm_segs++;
28740024Sgibbs				}
28856979Sgibbs				sg_block->sg_cnt = i;
28956979Sgibbs				sg_index += i;
29040024Sgibbs				if (dm_segs == end_seg) {
29140024Sgibbs					sg_block->sg_busaddr_next = 0;
29240024Sgibbs					break;
29340024Sgibbs				} else {
29440024Sgibbs					sg_busaddr +=
29540024Sgibbs					    sizeof(struct adw_sg_block);
29640024Sgibbs					sg_block->sg_busaddr_next = sg_busaddr;
29740024Sgibbs				}
29840024Sgibbs			}
29940024Sgibbs			acb->queue.sg_real_addr = acb->sg_busaddr;
30040024Sgibbs		} else {
30140024Sgibbs			acb->queue.sg_real_addr = 0;
30240024Sgibbs		}
30340024Sgibbs
30440024Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
30540024Sgibbs			op = BUS_DMASYNC_PREREAD;
30640024Sgibbs		else
30740024Sgibbs			op = BUS_DMASYNC_PREWRITE;
30840024Sgibbs
30940024Sgibbs		bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
31040024Sgibbs
31140024Sgibbs	} else {
31240024Sgibbs		acb->queue.data_addr = 0;
31340024Sgibbs		acb->queue.data_cnt = 0;
31440024Sgibbs		acb->queue.sg_real_addr = 0;
31540024Sgibbs	}
31640024Sgibbs
31740024Sgibbs	s = splcam();
31840024Sgibbs
31940024Sgibbs	/*
32040024Sgibbs	 * Last time we need to check if this CCB needs to
32140024Sgibbs	 * be aborted.
32240024Sgibbs	 */
32340024Sgibbs	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
32440024Sgibbs		if (nseg != 0)
32540024Sgibbs			bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
32640024Sgibbs		adwfreeacb(adw, acb);
32740024Sgibbs		xpt_done(ccb);
32840024Sgibbs		splx(s);
32940024Sgibbs		return;
33040024Sgibbs	}
33157679Sgibbs
33240024Sgibbs	acb->state |= ACB_ACTIVE;
33340024Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
33440024Sgibbs	LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le);
33540024Sgibbs	ccb->ccb_h.timeout_ch =
33640024Sgibbs	    timeout(adwtimeout, (caddr_t)acb,
33740024Sgibbs		    (ccb->ccb_h.timeout * hz) / 1000);
33840024Sgibbs
33956979Sgibbs	adw_send_acb(adw, acb, acbvtob(adw, acb));
34040024Sgibbs
34140024Sgibbs	splx(s);
34240024Sgibbs}
34340024Sgibbs
34440024Sgibbsstatic void
34540024Sgibbsadw_action(struct cam_sim *sim, union ccb *ccb)
34640024Sgibbs{
34740024Sgibbs	struct	adw_softc *adw;
34840024Sgibbs
34940024Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adw_action\n"));
35040024Sgibbs
35140024Sgibbs	adw = (struct adw_softc *)cam_sim_softc(sim);
35240024Sgibbs
35340024Sgibbs	switch (ccb->ccb_h.func_code) {
35440024Sgibbs	/* Common cases first */
35540024Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
35640024Sgibbs	{
35740024Sgibbs		struct	ccb_scsiio *csio;
35840024Sgibbs		struct	ccb_hdr *ccbh;
35940024Sgibbs		struct	acb *acb;
36040024Sgibbs
36140024Sgibbs		csio = &ccb->csio;
36240024Sgibbs		ccbh = &ccb->ccb_h;
36356979Sgibbs
36440024Sgibbs		/* Max supported CDB length is 12 bytes */
36540024Sgibbs		if (csio->cdb_len > 12) {
36640024Sgibbs			ccb->ccb_h.status = CAM_REQ_INVALID;
36740024Sgibbs			xpt_done(ccb);
36840024Sgibbs			return;
36940024Sgibbs		}
37040024Sgibbs
37140024Sgibbs		if ((acb = adwgetacb(adw)) == NULL) {
37240024Sgibbs			int s;
37340024Sgibbs
37440024Sgibbs			s = splcam();
37540024Sgibbs			adw->state |= ADW_RESOURCE_SHORTAGE;
37640024Sgibbs			splx(s);
37740024Sgibbs			xpt_freeze_simq(sim, /*count*/1);
37840024Sgibbs			ccb->ccb_h.status = CAM_REQUEUE_REQ;
37940024Sgibbs			xpt_done(ccb);
38040024Sgibbs			return;
38140024Sgibbs		}
38240024Sgibbs
38356979Sgibbs		/* Link acb and ccb so we can find one from the other */
38440024Sgibbs		acb->ccb = ccb;
38540024Sgibbs		ccb->ccb_h.ccb_acb_ptr = acb;
38640024Sgibbs		ccb->ccb_h.ccb_adw_ptr = adw;
38740024Sgibbs
38840024Sgibbs		acb->queue.cntl = 0;
38956979Sgibbs		acb->queue.target_cmd = 0;
39040024Sgibbs		acb->queue.target_id = ccb->ccb_h.target_id;
39140024Sgibbs		acb->queue.target_lun = ccb->ccb_h.target_lun;
39240024Sgibbs
39356979Sgibbs		acb->queue.mflag = 0;
39440024Sgibbs		acb->queue.sense_len =
39540024Sgibbs			MIN(csio->sense_len, sizeof(acb->sense_data));
39640024Sgibbs		acb->queue.cdb_len = csio->cdb_len;
39756979Sgibbs		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
39856979Sgibbs			switch (csio->tag_action) {
39956979Sgibbs			case MSG_SIMPLE_Q_TAG:
40057679Sgibbs				acb->queue.scsi_cntl = ADW_QSC_SIMPLE_Q_TAG;
40156979Sgibbs				break;
40256979Sgibbs			case MSG_HEAD_OF_Q_TAG:
40356979Sgibbs				acb->queue.scsi_cntl = ADW_QSC_HEAD_OF_Q_TAG;
40456979Sgibbs				break;
40556979Sgibbs			case MSG_ORDERED_Q_TAG:
40656979Sgibbs				acb->queue.scsi_cntl = ADW_QSC_ORDERED_Q_TAG;
40756979Sgibbs				break;
40857679Sgibbs			default:
40957679Sgibbs				acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
41057679Sgibbs				break;
41156979Sgibbs			}
41256979Sgibbs		} else
41356979Sgibbs			acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
41440024Sgibbs
41556979Sgibbs		if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
41656979Sgibbs			acb->queue.scsi_cntl |= ADW_QSC_NO_DISC;
41740024Sgibbs
41840024Sgibbs		acb->queue.done_status = 0;
41940024Sgibbs		acb->queue.scsi_status = 0;
42040024Sgibbs		acb->queue.host_status = 0;
42156979Sgibbs		acb->queue.sg_wk_ix = 0;
42240024Sgibbs		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
42340024Sgibbs			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
42440024Sgibbs				bcopy(csio->cdb_io.cdb_ptr,
42540024Sgibbs				      acb->queue.cdb, csio->cdb_len);
42640024Sgibbs			} else {
42740024Sgibbs				/* I guess I could map it in... */
42840024Sgibbs				ccb->ccb_h.status = CAM_REQ_INVALID;
42940024Sgibbs				adwfreeacb(adw, acb);
43040024Sgibbs				xpt_done(ccb);
43140024Sgibbs				return;
43240024Sgibbs			}
43340024Sgibbs		} else {
43440024Sgibbs			bcopy(csio->cdb_io.cdb_bytes,
43540024Sgibbs			      acb->queue.cdb, csio->cdb_len);
43640024Sgibbs		}
43740024Sgibbs
43840024Sgibbs		/*
43940024Sgibbs		 * If we have any data to send with this command,
44040024Sgibbs		 * map it into bus space.
44140024Sgibbs		 */
44240024Sgibbs		if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
44340024Sgibbs			if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
44440024Sgibbs				/*
44540024Sgibbs				 * We've been given a pointer
44640024Sgibbs				 * to a single buffer.
44740024Sgibbs				 */
44840024Sgibbs				if ((ccbh->flags & CAM_DATA_PHYS) == 0) {
44940024Sgibbs					int s;
45040024Sgibbs					int error;
45140024Sgibbs
45240024Sgibbs					s = splsoftvm();
45340024Sgibbs					error =
45440024Sgibbs					    bus_dmamap_load(adw->buffer_dmat,
45540024Sgibbs							    acb->dmamap,
45640024Sgibbs							    csio->data_ptr,
45740024Sgibbs							    csio->dxfer_len,
45840024Sgibbs							    adwexecuteacb,
45940024Sgibbs							    acb, /*flags*/0);
46040024Sgibbs					if (error == EINPROGRESS) {
46140024Sgibbs						/*
46240024Sgibbs						 * So as to maintain ordering,
46340024Sgibbs						 * freeze the controller queue
46440024Sgibbs						 * until our mapping is
46540024Sgibbs						 * returned.
46640024Sgibbs						 */
46740024Sgibbs						xpt_freeze_simq(sim, 1);
46840024Sgibbs						acb->state |= CAM_RELEASE_SIMQ;
46940024Sgibbs					}
47040024Sgibbs					splx(s);
47140024Sgibbs				} else {
47240024Sgibbs					struct bus_dma_segment seg;
47340024Sgibbs
47440024Sgibbs					/* Pointer to physical buffer */
47540024Sgibbs					seg.ds_addr =
47640024Sgibbs					    (bus_addr_t)csio->data_ptr;
47740024Sgibbs					seg.ds_len = csio->dxfer_len;
47840024Sgibbs					adwexecuteacb(acb, &seg, 1, 0);
47940024Sgibbs				}
48040024Sgibbs			} else {
48140024Sgibbs				struct bus_dma_segment *segs;
48240024Sgibbs
48340024Sgibbs				if ((ccbh->flags & CAM_DATA_PHYS) != 0)
48440024Sgibbs					panic("adw_action - Physical "
48540024Sgibbs					      "segment pointers "
48640024Sgibbs					      "unsupported");
48740024Sgibbs
48840024Sgibbs				if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
48940024Sgibbs					panic("adw_action - Virtual "
49040024Sgibbs					      "segment addresses "
49140024Sgibbs					      "unsupported");
49240024Sgibbs
49340024Sgibbs				/* Just use the segments provided */
49440024Sgibbs				segs = (struct bus_dma_segment *)csio->data_ptr;
49540024Sgibbs				adwexecuteacb(acb, segs, csio->sglist_cnt,
49640024Sgibbs					      (csio->sglist_cnt < ADW_SGSIZE)
49740024Sgibbs					      ? 0 : EFBIG);
49840024Sgibbs			}
49940024Sgibbs		} else {
50040024Sgibbs			adwexecuteacb(acb, NULL, 0, 0);
50140024Sgibbs		}
50240024Sgibbs		break;
50340024Sgibbs	}
50440024Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
50540024Sgibbs	{
50640024Sgibbs		adw_idle_cmd_status_t status;
50740024Sgibbs
50857679Sgibbs		status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
50957679Sgibbs					   ccb->ccb_h.target_id);
51040024Sgibbs		if (status == ADW_IDLE_CMD_SUCCESS) {
51140024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
51240024Sgibbs			if (bootverbose) {
51340024Sgibbs				xpt_print_path(ccb->ccb_h.path);
51440024Sgibbs				printf("BDR Delivered\n");
51540024Sgibbs			}
51640024Sgibbs		} else
51740024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
51840024Sgibbs		xpt_done(ccb);
51940024Sgibbs		break;
52040024Sgibbs	}
52140024Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
52240024Sgibbs		/* XXX Implement */
52340024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
52440024Sgibbs		xpt_done(ccb);
52540024Sgibbs		break;
52640024Sgibbs	case XPT_SET_TRAN_SETTINGS:
52740024Sgibbs	{
528163816Smjacob#ifdef	CAM_NEW_TRAN_CODE
529163816Smjacob		struct ccb_trans_settings_scsi *scsi;
530163816Smjacob		struct ccb_trans_settings_spi *spi;
531163816Smjacob#endif
53240024Sgibbs		struct	  ccb_trans_settings *cts;
53340024Sgibbs		u_int	  target_mask;
53440024Sgibbs		int	  s;
53540024Sgibbs
53640024Sgibbs		cts = &ccb->cts;
53740024Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
53840024Sgibbs
53940024Sgibbs		s = splcam();
540163816Smjacob#ifdef	CAM_NEW_TRAN_CODE
541163816Smjacob		scsi = &cts->proto_specific.scsi;
542163816Smjacob		spi = &cts->xport_specific.spi;
543163816Smjacob		if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
544163816Smjacob			u_int sdtrdone;
545163816Smjacob
546163816Smjacob			sdtrdone = adw_lram_read_16(adw, ADW_MC_SDTR_DONE);
547163816Smjacob			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
548163816Smjacob				u_int discenb;
549163816Smjacob
550163816Smjacob				discenb =
551163816Smjacob				    adw_lram_read_16(adw, ADW_MC_DISC_ENABLE);
552163816Smjacob
553163816Smjacob				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
554163816Smjacob					discenb |= target_mask;
555163816Smjacob				else
556163816Smjacob					discenb &= ~target_mask;
557163816Smjacob
558163816Smjacob				adw_lram_write_16(adw, ADW_MC_DISC_ENABLE,
559163816Smjacob						  discenb);
560163816Smjacob			}
561163816Smjacob
562163816Smjacob			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
563163816Smjacob
564163816Smjacob				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
565163816Smjacob					adw->tagenb |= target_mask;
566163816Smjacob				else
567163816Smjacob					adw->tagenb &= ~target_mask;
568163816Smjacob			}
569163816Smjacob
570163816Smjacob			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
571163816Smjacob				u_int wdtrenb_orig;
572163816Smjacob				u_int wdtrenb;
573163816Smjacob				u_int wdtrdone;
574163816Smjacob
575163816Smjacob				wdtrenb_orig =
576163816Smjacob				    adw_lram_read_16(adw, ADW_MC_WDTR_ABLE);
577163816Smjacob				wdtrenb = wdtrenb_orig;
578163816Smjacob				wdtrdone = adw_lram_read_16(adw,
579163816Smjacob							    ADW_MC_WDTR_DONE);
580163816Smjacob				switch (spi->bus_width) {
581163816Smjacob				case MSG_EXT_WDTR_BUS_32_BIT:
582163816Smjacob				case MSG_EXT_WDTR_BUS_16_BIT:
583163816Smjacob					wdtrenb |= target_mask;
584163816Smjacob					break;
585163816Smjacob				case MSG_EXT_WDTR_BUS_8_BIT:
586163816Smjacob				default:
587163816Smjacob					wdtrenb &= ~target_mask;
588163816Smjacob					break;
589163816Smjacob				}
590163816Smjacob				if (wdtrenb != wdtrenb_orig) {
591163816Smjacob					adw_lram_write_16(adw,
592163816Smjacob							  ADW_MC_WDTR_ABLE,
593163816Smjacob							  wdtrenb);
594163816Smjacob					wdtrdone &= ~target_mask;
595163816Smjacob					adw_lram_write_16(adw,
596163816Smjacob							  ADW_MC_WDTR_DONE,
597163816Smjacob							  wdtrdone);
598163816Smjacob					/* Wide negotiation forces async */
599163816Smjacob					sdtrdone &= ~target_mask;
600163816Smjacob					adw_lram_write_16(adw,
601163816Smjacob							  ADW_MC_SDTR_DONE,
602163816Smjacob							  sdtrdone);
603163816Smjacob				}
604163816Smjacob			}
605163816Smjacob
606163816Smjacob			if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0)
607163816Smjacob			 || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) {
608163816Smjacob				u_int sdtr_orig;
609163816Smjacob				u_int sdtr;
610163816Smjacob				u_int sdtrable_orig;
611163816Smjacob				u_int sdtrable;
612163816Smjacob
613163816Smjacob				sdtr = adw_get_chip_sdtr(adw,
614163816Smjacob							 ccb->ccb_h.target_id);
615163816Smjacob				sdtr_orig = sdtr;
616163816Smjacob				sdtrable = adw_lram_read_16(adw,
617163816Smjacob							    ADW_MC_SDTR_ABLE);
618163816Smjacob				sdtrable_orig = sdtrable;
619163816Smjacob
620163816Smjacob				if ((spi->valid
621163816Smjacob				   & CTS_SPI_VALID_SYNC_RATE) != 0) {
622163816Smjacob
623163816Smjacob					sdtr =
624163816Smjacob					    adw_find_sdtr(adw,
625163816Smjacob							  spi->sync_period);
626163816Smjacob				}
627163816Smjacob
628163816Smjacob				if ((spi->valid
629163816Smjacob				   & CTS_SPI_VALID_SYNC_OFFSET) != 0) {
630163816Smjacob					if (spi->sync_offset == 0)
631163816Smjacob						sdtr = ADW_MC_SDTR_ASYNC;
632163816Smjacob				}
633163816Smjacob
634163816Smjacob				if (sdtr == ADW_MC_SDTR_ASYNC)
635163816Smjacob					sdtrable &= ~target_mask;
636163816Smjacob				else
637163816Smjacob					sdtrable |= target_mask;
638163816Smjacob				if (sdtr != sdtr_orig
639163816Smjacob				 || sdtrable != sdtrable_orig) {
640163816Smjacob					adw_set_chip_sdtr(adw,
641163816Smjacob							  ccb->ccb_h.target_id,
642163816Smjacob							  sdtr);
643163816Smjacob					sdtrdone &= ~target_mask;
644163816Smjacob					adw_lram_write_16(adw, ADW_MC_SDTR_ABLE,
645163816Smjacob							  sdtrable);
646163816Smjacob					adw_lram_write_16(adw, ADW_MC_SDTR_DONE,
647163816Smjacob							  sdtrdone);
648163816Smjacob
649163816Smjacob				}
650163816Smjacob			}
651163816Smjacob		}
652163816Smjacob#else
65340024Sgibbs		if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
65456979Sgibbs			u_int sdtrdone;
65556979Sgibbs
65656979Sgibbs			sdtrdone = adw_lram_read_16(adw, ADW_MC_SDTR_DONE);
65740024Sgibbs			if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
65840024Sgibbs				u_int discenb;
65940024Sgibbs
66040024Sgibbs				discenb =
66140024Sgibbs				    adw_lram_read_16(adw, ADW_MC_DISC_ENABLE);
66240024Sgibbs
66340024Sgibbs				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
66440024Sgibbs					discenb |= target_mask;
66540024Sgibbs				else
66640024Sgibbs					discenb &= ~target_mask;
66740024Sgibbs
66840024Sgibbs				adw_lram_write_16(adw, ADW_MC_DISC_ENABLE,
66940024Sgibbs						  discenb);
67040024Sgibbs			}
67140024Sgibbs
67240024Sgibbs			if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
67340024Sgibbs
67440024Sgibbs				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
67540024Sgibbs					adw->tagenb |= target_mask;
67640024Sgibbs				else
67740024Sgibbs					adw->tagenb &= ~target_mask;
67840024Sgibbs			}
67940024Sgibbs
68040024Sgibbs			if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
68140024Sgibbs				u_int wdtrenb_orig;
68240024Sgibbs				u_int wdtrenb;
68340024Sgibbs				u_int wdtrdone;
68440024Sgibbs
68540024Sgibbs				wdtrenb_orig =
68640024Sgibbs				    adw_lram_read_16(adw, ADW_MC_WDTR_ABLE);
68740024Sgibbs				wdtrenb = wdtrenb_orig;
68840024Sgibbs				wdtrdone = adw_lram_read_16(adw,
68940024Sgibbs							    ADW_MC_WDTR_DONE);
69040024Sgibbs				switch (cts->bus_width) {
69140024Sgibbs				case MSG_EXT_WDTR_BUS_32_BIT:
69240024Sgibbs				case MSG_EXT_WDTR_BUS_16_BIT:
69340024Sgibbs					wdtrenb |= target_mask;
69440024Sgibbs					break;
69540024Sgibbs				case MSG_EXT_WDTR_BUS_8_BIT:
69640024Sgibbs				default:
69740024Sgibbs					wdtrenb &= ~target_mask;
69840024Sgibbs					break;
69940024Sgibbs				}
70040024Sgibbs				if (wdtrenb != wdtrenb_orig) {
70140024Sgibbs					adw_lram_write_16(adw,
70240024Sgibbs							  ADW_MC_WDTR_ABLE,
70340024Sgibbs							  wdtrenb);
70440024Sgibbs					wdtrdone &= ~target_mask;
70540024Sgibbs					adw_lram_write_16(adw,
70640024Sgibbs							  ADW_MC_WDTR_DONE,
70740024Sgibbs							  wdtrdone);
70856979Sgibbs					/* Wide negotiation forces async */
70956979Sgibbs					sdtrdone &= ~target_mask;
71056979Sgibbs					adw_lram_write_16(adw,
71156979Sgibbs							  ADW_MC_SDTR_DONE,
71256979Sgibbs							  sdtrdone);
71340024Sgibbs				}
71440024Sgibbs			}
71540024Sgibbs
71646581Sken			if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
71746581Sken			 || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
71856979Sgibbs				u_int sdtr_orig;
71956979Sgibbs				u_int sdtr;
72056979Sgibbs				u_int sdtrable_orig;
72156979Sgibbs				u_int sdtrable;
72240024Sgibbs
72356979Sgibbs				sdtr = adw_get_chip_sdtr(adw,
72456979Sgibbs							 ccb->ccb_h.target_id);
72556979Sgibbs				sdtr_orig = sdtr;
72656979Sgibbs				sdtrable = adw_lram_read_16(adw,
72756979Sgibbs							    ADW_MC_SDTR_ABLE);
72856979Sgibbs				sdtrable_orig = sdtrable;
72940024Sgibbs
73046581Sken				if ((cts->valid
73146581Sken				   & CCB_TRANS_SYNC_RATE_VALID) != 0) {
73246581Sken
73356979Sgibbs					sdtr =
73456979Sgibbs					    adw_find_sdtr(adw,
73556979Sgibbs							  cts->sync_period);
73640024Sgibbs				}
73740024Sgibbs
73840024Sgibbs				if ((cts->valid
73940024Sgibbs				   & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
74040024Sgibbs					if (cts->sync_offset == 0)
74156979Sgibbs						sdtr = ADW_MC_SDTR_ASYNC;
74240024Sgibbs				}
74340024Sgibbs
74456979Sgibbs				if (sdtr == ADW_MC_SDTR_ASYNC)
74556979Sgibbs					sdtrable &= ~target_mask;
74656979Sgibbs				else
74756979Sgibbs					sdtrable |= target_mask;
74856979Sgibbs				if (sdtr != sdtr_orig
74956979Sgibbs				 || sdtrable != sdtrable_orig) {
75056979Sgibbs					adw_set_chip_sdtr(adw,
75156979Sgibbs							  ccb->ccb_h.target_id,
75256979Sgibbs							  sdtr);
75356979Sgibbs					sdtrdone &= ~target_mask;
75440024Sgibbs					adw_lram_write_16(adw, ADW_MC_SDTR_ABLE,
75556979Sgibbs							  sdtrable);
75640024Sgibbs					adw_lram_write_16(adw, ADW_MC_SDTR_DONE,
75740024Sgibbs							  sdtrdone);
75856979Sgibbs
75940024Sgibbs				}
76040024Sgibbs			}
76140024Sgibbs		}
762163816Smjacob#endif
76340024Sgibbs		splx(s);
76440024Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
76540024Sgibbs		xpt_done(ccb);
76640024Sgibbs		break;
76740024Sgibbs	}
76840024Sgibbs	case XPT_GET_TRAN_SETTINGS:
76940024Sgibbs	/* Get default/user set transfer settings for the target */
77040024Sgibbs	{
771163816Smjacob#ifdef	CAM_NEW_TRAN_CODE
772163816Smjacob		struct ccb_trans_settings_scsi *scsi;
773163816Smjacob		struct ccb_trans_settings_spi *spi;
774163816Smjacob#endif
77540024Sgibbs		struct	ccb_trans_settings *cts;
77640024Sgibbs		u_int	target_mask;
77740024Sgibbs
77840024Sgibbs		cts = &ccb->cts;
77940024Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
780163816Smjacob#ifdef	CAM_NEW_TRAN_CODE
781163816Smjacob		cts->protocol = PROTO_SCSI;
782163816Smjacob		cts->protocol_version = SCSI_REV_2;
783163816Smjacob		cts->transport = XPORT_SPI;
784163816Smjacob		cts->transport_version = 2;
785163816Smjacob
786163816Smjacob		scsi = &cts->proto_specific.scsi;
787163816Smjacob		spi = &cts->xport_specific.spi;
788163816Smjacob		if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
78956979Sgibbs			u_int mc_sdtr;
79056979Sgibbs
791163816Smjacob			spi->flags = 0;
792163816Smjacob			if ((adw->user_discenb & target_mask) != 0)
793163816Smjacob				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
794163816Smjacob
795163816Smjacob			if ((adw->user_tagenb & target_mask) != 0)
796163816Smjacob				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
797163816Smjacob
798163816Smjacob			if ((adw->user_wdtr & target_mask) != 0)
799163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
800163816Smjacob			else
801163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
802163816Smjacob
803163816Smjacob			mc_sdtr = adw_get_user_sdtr(adw, ccb->ccb_h.target_id);
804163816Smjacob			spi->sync_period = adw_find_period(adw, mc_sdtr);
805163816Smjacob			if (spi->sync_period != 0)
806163816Smjacob				spi->sync_offset = 15; /* XXX ??? */
807163816Smjacob			else
808163816Smjacob				spi->sync_offset = 0;
809163816Smjacob
810163816Smjacob
811163816Smjacob		} else {
812163816Smjacob			u_int targ_tinfo;
813163816Smjacob
814163816Smjacob			spi->flags = 0;
815163816Smjacob			if ((adw_lram_read_16(adw, ADW_MC_DISC_ENABLE)
816163816Smjacob			  & target_mask) != 0)
817163816Smjacob				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
818163816Smjacob
819163816Smjacob			if ((adw->tagenb & target_mask) != 0)
820163816Smjacob				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
821163816Smjacob
822163816Smjacob			targ_tinfo =
823163816Smjacob			    adw_lram_read_16(adw,
824163816Smjacob					     ADW_MC_DEVICE_HSHK_CFG_TABLE
825163816Smjacob					     + (2 * ccb->ccb_h.target_id));
826163816Smjacob
827163816Smjacob			if ((targ_tinfo & ADW_HSHK_CFG_WIDE_XFR) != 0)
828163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
829163816Smjacob			else
830163816Smjacob				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
831163816Smjacob
832163816Smjacob			spi->sync_period =
833163816Smjacob			    adw_hshk_cfg_period_factor(targ_tinfo);
834163816Smjacob
835163816Smjacob			spi->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET;
836163816Smjacob			if (spi->sync_period == 0)
837163816Smjacob				spi->sync_offset = 0;
838163816Smjacob
839163816Smjacob			if (spi->sync_offset == 0)
840163816Smjacob				spi->sync_period = 0;
841163816Smjacob		}
842163816Smjacob
843163816Smjacob		spi->valid = CTS_SPI_VALID_SYNC_RATE
844163816Smjacob			   | CTS_SPI_VALID_SYNC_OFFSET
845163816Smjacob			   | CTS_SPI_VALID_BUS_WIDTH
846163816Smjacob			   | CTS_SPI_VALID_DISC;
847163816Smjacob		scsi->valid = CTS_SCSI_VALID_TQ;
848163816Smjacob#else
849163816Smjacob		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
850163816Smjacob			u_int mc_sdtr;
851163816Smjacob
85240024Sgibbs			cts->flags = 0;
85340024Sgibbs			if ((adw->user_discenb & target_mask) != 0)
85440024Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
85540024Sgibbs
85640024Sgibbs			if ((adw->user_tagenb & target_mask) != 0)
85740024Sgibbs				cts->flags |= CCB_TRANS_TAG_ENB;
85840024Sgibbs
85940024Sgibbs			if ((adw->user_wdtr & target_mask) != 0)
86040024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
86140024Sgibbs			else
86240024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
86340024Sgibbs
86456979Sgibbs			mc_sdtr = adw_get_user_sdtr(adw, ccb->ccb_h.target_id);
86556979Sgibbs			cts->sync_period = adw_find_period(adw, mc_sdtr);
86656979Sgibbs			if (cts->sync_period != 0)
86740024Sgibbs				cts->sync_offset = 15; /* XXX ??? */
86856979Sgibbs			else
86956979Sgibbs				cts->sync_offset = 0;
87040024Sgibbs
87140024Sgibbs			cts->valid = CCB_TRANS_SYNC_RATE_VALID
87240024Sgibbs				   | CCB_TRANS_SYNC_OFFSET_VALID
87340024Sgibbs				   | CCB_TRANS_BUS_WIDTH_VALID
87440024Sgibbs				   | CCB_TRANS_DISC_VALID
87540024Sgibbs				   | CCB_TRANS_TQ_VALID;
87640024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
87740024Sgibbs		} else {
87840024Sgibbs			u_int targ_tinfo;
87940024Sgibbs
88040024Sgibbs			cts->flags = 0;
88140024Sgibbs			if ((adw_lram_read_16(adw, ADW_MC_DISC_ENABLE)
88240024Sgibbs			  & target_mask) != 0)
88340024Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
88440024Sgibbs
88540024Sgibbs			if ((adw->tagenb & target_mask) != 0)
88640024Sgibbs				cts->flags |= CCB_TRANS_TAG_ENB;
88740024Sgibbs
88840024Sgibbs			targ_tinfo =
88940024Sgibbs			    adw_lram_read_16(adw,
89040024Sgibbs					     ADW_MC_DEVICE_HSHK_CFG_TABLE
89140024Sgibbs					     + (2 * ccb->ccb_h.target_id));
89240024Sgibbs
89340024Sgibbs			if ((targ_tinfo & ADW_HSHK_CFG_WIDE_XFR) != 0)
89440024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
89540024Sgibbs			else
89640024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
89740024Sgibbs
89840024Sgibbs			cts->sync_period =
89956979Sgibbs			    adw_hshk_cfg_period_factor(targ_tinfo);
90040024Sgibbs
90140024Sgibbs			cts->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET;
90240024Sgibbs			if (cts->sync_period == 0)
90340024Sgibbs				cts->sync_offset = 0;
90440024Sgibbs
90540024Sgibbs			if (cts->sync_offset == 0)
90640024Sgibbs				cts->sync_period = 0;
90740024Sgibbs		}
90840024Sgibbs		cts->valid = CCB_TRANS_SYNC_RATE_VALID
90940024Sgibbs			   | CCB_TRANS_SYNC_OFFSET_VALID
91040024Sgibbs			   | CCB_TRANS_BUS_WIDTH_VALID
91140024Sgibbs			   | CCB_TRANS_DISC_VALID
91240024Sgibbs			   | CCB_TRANS_TQ_VALID;
913163816Smjacob#endif
91440024Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
91540024Sgibbs		xpt_done(ccb);
91640024Sgibbs		break;
91740024Sgibbs	}
91840024Sgibbs	case XPT_CALC_GEOMETRY:
91940024Sgibbs	{
92040024Sgibbs		/*
92140024Sgibbs		 * XXX Use Adaptec translation until I find out how to
92240024Sgibbs		 *     get this information from the card.
92340024Sgibbs		 */
924116351Snjl		cam_calc_geometry(&ccb->ccg, /*extended*/1);
92540024Sgibbs		xpt_done(ccb);
92640024Sgibbs		break;
92740024Sgibbs	}
92840024Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
92940024Sgibbs	{
93057679Sgibbs		int failure;
93140024Sgibbs
93257679Sgibbs		failure = adw_reset_bus(adw);
93357679Sgibbs		if (failure != 0) {
93440024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
93557679Sgibbs		} else {
93657679Sgibbs			if (bootverbose) {
93757679Sgibbs				xpt_print_path(adw->path);
93857679Sgibbs				printf("Bus Reset Delivered\n");
93957679Sgibbs			}
94057679Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
94156979Sgibbs		}
94240024Sgibbs		xpt_done(ccb);
94340024Sgibbs		break;
94440024Sgibbs	}
94540024Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
94640024Sgibbs		/* XXX Implement */
94740024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
94840024Sgibbs		xpt_done(ccb);
94940024Sgibbs		break;
95040024Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
95140024Sgibbs	{
95240024Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
95340024Sgibbs
95440024Sgibbs		cpi->version_num = 1;
95540024Sgibbs		cpi->hba_inquiry = PI_WIDE_16|PI_SDTR_ABLE|PI_TAG_ABLE;
95640024Sgibbs		cpi->target_sprt = 0;
95740024Sgibbs		cpi->hba_misc = 0;
95840024Sgibbs		cpi->hba_eng_cnt = 0;
95940024Sgibbs		cpi->max_target = ADW_MAX_TID;
96040024Sgibbs		cpi->max_lun = ADW_MAX_LUN;
96140024Sgibbs		cpi->initiator_id = adw->initiator_id;
96240024Sgibbs		cpi->bus_id = cam_sim_bus(sim);
96346581Sken		cpi->base_transfer_speed = 3300;
96440024Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
96540024Sgibbs		strncpy(cpi->hba_vid, "AdvanSys", HBA_IDLEN);
96640024Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
96740024Sgibbs		cpi->unit_number = cam_sim_unit(sim);
968163816Smjacob#ifdef	CAM_NEW_TRAN_CODE
969163816Smjacob                cpi->transport = XPORT_SPI;
970163816Smjacob                cpi->transport_version = 2;
971163816Smjacob                cpi->protocol = PROTO_SCSI;
972163816Smjacob                cpi->protocol_version = SCSI_REV_2;
973163816Smjacob#endif
97440024Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
97540024Sgibbs		xpt_done(ccb);
97640024Sgibbs		break;
97740024Sgibbs	}
97840024Sgibbs	default:
97940024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
98040024Sgibbs		xpt_done(ccb);
98140024Sgibbs		break;
98240024Sgibbs	}
98340024Sgibbs}
98440024Sgibbs
98540024Sgibbsstatic void
98640024Sgibbsadw_poll(struct cam_sim *sim)
98740024Sgibbs{
98840024Sgibbs	adw_intr(cam_sim_softc(sim));
98940024Sgibbs}
99040024Sgibbs
99140024Sgibbsstatic void
99240024Sgibbsadw_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
99340024Sgibbs{
99440024Sgibbs}
99540024Sgibbs
99640024Sgibbsstruct adw_softc *
99756979Sgibbsadw_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id)
99840024Sgibbs{
99940024Sgibbs	struct	 adw_softc *adw;
100040024Sgibbs	int	 i;
100140024Sgibbs
100240024Sgibbs	/*
100340024Sgibbs	 * Allocate a storage area for us
100440024Sgibbs	 */
100567888Sdwmalone	adw = malloc(sizeof(struct adw_softc), M_DEVBUF, M_NOWAIT | M_ZERO);
100640024Sgibbs	if (adw == NULL) {
100756979Sgibbs		printf("adw%d: cannot malloc!\n", device_get_unit(dev));
100840024Sgibbs		return NULL;
100940024Sgibbs	}
101040024Sgibbs	LIST_INIT(&adw->pending_ccbs);
101140024Sgibbs	SLIST_INIT(&adw->sg_maps);
101256979Sgibbs	adw->device = dev;
101356979Sgibbs	adw->unit = device_get_unit(dev);
101456979Sgibbs	adw->regs_res_type = regs_type;
101556979Sgibbs	adw->regs_res_id = regs_id;
101656979Sgibbs	adw->regs = regs;
101756979Sgibbs	adw->tag = rman_get_bustag(regs);
101856979Sgibbs	adw->bsh = rman_get_bushandle(regs);
101940024Sgibbs	i = adw->unit / 10;
102040024Sgibbs	adw->name = malloc(sizeof("adw") + i + 1, M_DEVBUF, M_NOWAIT);
102140024Sgibbs	if (adw->name == NULL) {
102256979Sgibbs		printf("adw%d: cannot malloc name!\n", adw->unit);
102340024Sgibbs		free(adw, M_DEVBUF);
102440024Sgibbs		return NULL;
102540024Sgibbs	}
102640024Sgibbs	sprintf(adw->name, "adw%d", adw->unit);
102740024Sgibbs	return(adw);
102840024Sgibbs}
102940024Sgibbs
103040024Sgibbsvoid
103140024Sgibbsadw_free(struct adw_softc *adw)
103240024Sgibbs{
103340024Sgibbs	switch (adw->init_level) {
103456979Sgibbs	case 9:
103540024Sgibbs	{
103640024Sgibbs		struct sg_map_node *sg_map;
103740024Sgibbs
103840024Sgibbs		while ((sg_map = SLIST_FIRST(&adw->sg_maps)) != NULL) {
103940024Sgibbs			SLIST_REMOVE_HEAD(&adw->sg_maps, links);
104040024Sgibbs			bus_dmamap_unload(adw->sg_dmat,
104140024Sgibbs					  sg_map->sg_dmamap);
104240024Sgibbs			bus_dmamem_free(adw->sg_dmat, sg_map->sg_vaddr,
104340024Sgibbs					sg_map->sg_dmamap);
104440024Sgibbs			free(sg_map, M_DEVBUF);
104540024Sgibbs		}
104640024Sgibbs		bus_dma_tag_destroy(adw->sg_dmat);
104740024Sgibbs	}
104856979Sgibbs	case 8:
104940024Sgibbs		bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap);
105056979Sgibbs	case 7:
105140024Sgibbs		bus_dmamem_free(adw->acb_dmat, adw->acbs,
105240024Sgibbs				adw->acb_dmamap);
105340024Sgibbs		bus_dmamap_destroy(adw->acb_dmat, adw->acb_dmamap);
105456979Sgibbs	case 6:
105556979Sgibbs		bus_dma_tag_destroy(adw->acb_dmat);
105656979Sgibbs	case 5:
105756979Sgibbs		bus_dmamap_unload(adw->carrier_dmat, adw->carrier_dmamap);
105856979Sgibbs	case 4:
105956979Sgibbs		bus_dmamem_free(adw->carrier_dmat, adw->carriers,
106056979Sgibbs				adw->carrier_dmamap);
106156979Sgibbs		bus_dmamap_destroy(adw->carrier_dmat, adw->carrier_dmamap);
106240024Sgibbs	case 3:
106356979Sgibbs		bus_dma_tag_destroy(adw->carrier_dmat);
106440024Sgibbs	case 2:
106540024Sgibbs		bus_dma_tag_destroy(adw->buffer_dmat);
106640024Sgibbs	case 1:
106740024Sgibbs		bus_dma_tag_destroy(adw->parent_dmat);
106840024Sgibbs	case 0:
106940024Sgibbs		break;
107040024Sgibbs	}
1071138502Srsm
1072138502Srsm	if (adw->regs != NULL)
1073138502Srsm		bus_release_resource(adw->device,
1074138502Srsm				     adw->regs_res_type,
1075138502Srsm				     adw->regs_res_id,
1076138502Srsm				     adw->regs);
1077138502Srsm
1078138502Srsm	if (adw->irq != NULL)
1079138502Srsm		bus_release_resource(adw->device,
1080138502Srsm				     adw->irq_res_type,
1081138502Srsm				     0, adw->irq);
1082138502Srsm
1083138502Srsm	if (adw->sim != NULL) {
1084138502Srsm		if (adw->path != NULL) {
1085138502Srsm			xpt_async(AC_LOST_DEVICE, adw->path, NULL);
1086138502Srsm			xpt_free_path(adw->path);
1087138502Srsm		}
1088138502Srsm		xpt_bus_deregister(cam_sim_path(adw->sim));
1089138502Srsm		cam_sim_free(adw->sim, /*free_devq*/TRUE);
1090138502Srsm	}
109140024Sgibbs	free(adw->name, M_DEVBUF);
109240024Sgibbs	free(adw, M_DEVBUF);
109340024Sgibbs}
109440024Sgibbs
109540024Sgibbsint
109640024Sgibbsadw_init(struct adw_softc *adw)
109740024Sgibbs{
109840024Sgibbs	struct	  adw_eeprom eep_config;
109956979Sgibbs	u_int	  tid;
110056979Sgibbs	u_int	  i;
110140024Sgibbs	u_int16_t checksum;
110240024Sgibbs	u_int16_t scsicfg1;
110340024Sgibbs
110440024Sgibbs	checksum = adw_eeprom_read(adw, &eep_config);
110540024Sgibbs	bcopy(eep_config.serial_number, adw->serial_number,
110640024Sgibbs	      sizeof(adw->serial_number));
110740024Sgibbs	if (checksum != eep_config.checksum) {
110840024Sgibbs		u_int16_t serial_number[3];
110940024Sgibbs
111056979Sgibbs		adw->flags |= ADW_EEPROM_FAILED;
111140024Sgibbs		printf("%s: EEPROM checksum failed.  Restoring Defaults\n",
111240024Sgibbs		       adw_name(adw));
111340024Sgibbs
111440024Sgibbs	        /*
111540024Sgibbs		 * Restore the default EEPROM settings.
111640024Sgibbs		 * Assume the 6 byte board serial number that was read
111740024Sgibbs		 * from EEPROM is correct even if the EEPROM checksum
111840024Sgibbs		 * failed.
111940024Sgibbs		 */
112056979Sgibbs		bcopy(adw->default_eeprom, &eep_config, sizeof(eep_config));
112140024Sgibbs		bcopy(adw->serial_number, eep_config.serial_number,
112240024Sgibbs		      sizeof(serial_number));
112340024Sgibbs		adw_eeprom_write(adw, &eep_config);
112440024Sgibbs	}
112540024Sgibbs
112640024Sgibbs	/* Pull eeprom information into our softc. */
112740024Sgibbs	adw->bios_ctrl = eep_config.bios_ctrl;
112840024Sgibbs	adw->user_wdtr = eep_config.wdtr_able;
112956979Sgibbs	for (tid = 0; tid < ADW_MAX_TID; tid++) {
113056979Sgibbs		u_int	  mc_sdtr;
113156979Sgibbs		u_int16_t tid_mask;
113256979Sgibbs
113356979Sgibbs		tid_mask = 0x1 << tid;
113456979Sgibbs		if ((adw->features & ADW_ULTRA) != 0) {
113556979Sgibbs			/*
113656979Sgibbs			 * Ultra chips store sdtr and ultraenb
113756979Sgibbs			 * bits in their seeprom, so we must
113856979Sgibbs			 * construct valid mc_sdtr entries for
113956979Sgibbs			 * indirectly.
114056979Sgibbs			 */
114156979Sgibbs			if (eep_config.sync1.sync_enable & tid_mask) {
114256979Sgibbs				if (eep_config.sync2.ultra_enable & tid_mask)
114356979Sgibbs					mc_sdtr = ADW_MC_SDTR_20;
114456979Sgibbs				else
114556979Sgibbs					mc_sdtr = ADW_MC_SDTR_10;
114656979Sgibbs			} else
114756979Sgibbs				mc_sdtr = ADW_MC_SDTR_ASYNC;
114856979Sgibbs		} else {
114956979Sgibbs			switch (ADW_TARGET_GROUP(tid)) {
115056979Sgibbs			case 3:
115156979Sgibbs				mc_sdtr = eep_config.sync4.sdtr4;
115256979Sgibbs				break;
115356979Sgibbs			case 2:
115456979Sgibbs				mc_sdtr = eep_config.sync3.sdtr3;
115556979Sgibbs				break;
115656979Sgibbs			case 1:
115756979Sgibbs				mc_sdtr = eep_config.sync2.sdtr2;
115856979Sgibbs				break;
115956979Sgibbs			default: /* Shut up compiler */
116056979Sgibbs			case 0:
116156979Sgibbs				mc_sdtr = eep_config.sync1.sdtr1;
116256979Sgibbs				break;
116356979Sgibbs			}
116456979Sgibbs			mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid);
116556979Sgibbs			mc_sdtr &= 0xFF;
116656979Sgibbs		}
116756979Sgibbs		adw_set_user_sdtr(adw, tid, mc_sdtr);
116856979Sgibbs	}
116940024Sgibbs	adw->user_tagenb = eep_config.tagqng_able;
117040024Sgibbs	adw->user_discenb = eep_config.disc_enable;
117140024Sgibbs	adw->max_acbs = eep_config.max_host_qng;
117240024Sgibbs	adw->initiator_id = (eep_config.adapter_scsi_id & ADW_MAX_TID);
117340024Sgibbs
117440024Sgibbs	/*
117540024Sgibbs	 * Sanity check the number of host openings.
117640024Sgibbs	 */
117740024Sgibbs	if (adw->max_acbs > ADW_DEF_MAX_HOST_QNG)
117840024Sgibbs		adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
117940024Sgibbs	else if (adw->max_acbs < ADW_DEF_MIN_HOST_QNG) {
118040024Sgibbs        	/* If the value is zero, assume it is uninitialized. */
118140024Sgibbs		if (adw->max_acbs == 0)
118240024Sgibbs			adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
118340024Sgibbs		else
118440024Sgibbs			adw->max_acbs = ADW_DEF_MIN_HOST_QNG;
118540024Sgibbs	}
118640024Sgibbs
118740024Sgibbs	scsicfg1 = 0;
118856979Sgibbs	if ((adw->features & ADW_ULTRA2) != 0) {
118956979Sgibbs		switch (eep_config.termination_lvd) {
119056979Sgibbs		default:
119156979Sgibbs			printf("%s: Invalid EEPROM LVD Termination Settings.\n",
119256979Sgibbs			       adw_name(adw));
119356979Sgibbs			printf("%s: Reverting to Automatic LVD Termination\n",
119456979Sgibbs			       adw_name(adw));
119556979Sgibbs			/* FALLTHROUGH */
119656979Sgibbs		case ADW_EEPROM_TERM_AUTO:
119756979Sgibbs			break;
119856979Sgibbs		case ADW_EEPROM_TERM_BOTH_ON:
119956979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_LO;
120056979Sgibbs			/* FALLTHROUGH */
120156979Sgibbs		case ADW_EEPROM_TERM_HIGH_ON:
120256979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_HI;
120356979Sgibbs			/* FALLTHROUGH */
120456979Sgibbs		case ADW_EEPROM_TERM_OFF:
120556979Sgibbs			scsicfg1 |= ADW2_SCSI_CFG1_DIS_TERM_DRV;
120656979Sgibbs			break;
120756979Sgibbs		}
120856979Sgibbs	}
120956979Sgibbs
121056979Sgibbs	switch (eep_config.termination_se) {
121140024Sgibbs	default:
121256979Sgibbs		printf("%s: Invalid SE EEPROM Termination Settings.\n",
121340024Sgibbs		       adw_name(adw));
121456979Sgibbs		printf("%s: Reverting to Automatic SE Termination\n",
121540024Sgibbs		       adw_name(adw));
121640024Sgibbs		/* FALLTHROUGH */
121740024Sgibbs	case ADW_EEPROM_TERM_AUTO:
121840024Sgibbs		break;
121940024Sgibbs	case ADW_EEPROM_TERM_BOTH_ON:
122040024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L;
122140024Sgibbs		/* FALLTHROUGH */
122240024Sgibbs	case ADW_EEPROM_TERM_HIGH_ON:
122340024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H;
122440024Sgibbs		/* FALLTHROUGH */
122540024Sgibbs	case ADW_EEPROM_TERM_OFF:
122640024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL;
122740024Sgibbs		break;
122840024Sgibbs	}
122940024Sgibbs	printf("%s: SCSI ID %d, ", adw_name(adw), adw->initiator_id);
123040024Sgibbs
123140024Sgibbs	/* DMA tag for mapping buffers into device visible space. */
1232112782Smdodd	if (bus_dma_tag_create(
1233112782Smdodd			/* parent	*/ adw->parent_dmat,
1234112782Smdodd			/* alignment	*/ 1,
1235112782Smdodd			/* boundary	*/ 0,
1236112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
1237112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1238112782Smdodd			/* filter	*/ NULL,
1239112782Smdodd			/* filterarg	*/ NULL,
1240112782Smdodd			/* maxsize	*/ MAXBSIZE,
1241112782Smdodd			/* nsegments	*/ ADW_SGSIZE,
1242112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1243112782Smdodd			/* flags	*/ BUS_DMA_ALLOCNOW,
1244117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1245117126Sscottl			/* lockarg	*/ &Giant,
1246112782Smdodd			&adw->buffer_dmat) != 0) {
124756979Sgibbs		return (ENOMEM);
124840024Sgibbs	}
124940024Sgibbs
125040024Sgibbs	adw->init_level++;
125140024Sgibbs
125256979Sgibbs	/* DMA tag for our ccb carrier structures */
1253112782Smdodd	if (bus_dma_tag_create(
1254112782Smdodd			/* parent	*/ adw->parent_dmat,
1255112782Smdodd			/* alignment	*/ 0x10,
1256112782Smdodd			/* boundary	*/ 0,
1257112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
1258112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1259112782Smdodd			/* filter	*/ NULL,
1260112782Smdodd			/* filterarg	*/ NULL,
1261112782Smdodd			/* maxsize	*/ (adw->max_acbs +
1262112782Smdodd					    ADW_NUM_CARRIER_QUEUES + 1) *
1263112782Smdodd					    sizeof(struct adw_carrier),
1264112782Smdodd			/* nsegments	*/ 1,
1265112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1266112782Smdodd			/* flags	*/ 0,
1267117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1268117126Sscottl			/* lockarg	*/ &Giant,
1269112782Smdodd			&adw->carrier_dmat) != 0) {
127056979Sgibbs		return (ENOMEM);
127156979Sgibbs        }
127256979Sgibbs
127356979Sgibbs	adw->init_level++;
127456979Sgibbs
127556979Sgibbs	/* Allocation for our ccb carrier structures */
127656979Sgibbs	if (bus_dmamem_alloc(adw->carrier_dmat, (void **)&adw->carriers,
127756979Sgibbs			     BUS_DMA_NOWAIT, &adw->carrier_dmamap) != 0) {
127856979Sgibbs		return (ENOMEM);
127956979Sgibbs	}
128056979Sgibbs
128156979Sgibbs	adw->init_level++;
128256979Sgibbs
128356979Sgibbs	/* And permanently map them */
128456979Sgibbs	bus_dmamap_load(adw->carrier_dmat, adw->carrier_dmamap,
128556979Sgibbs			adw->carriers,
128656979Sgibbs			(adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
128756979Sgibbs			 * sizeof(struct adw_carrier),
128856979Sgibbs			adwmapmem, &adw->carrier_busbase, /*flags*/0);
128956979Sgibbs
129056979Sgibbs	/* Clear them out. */
129156979Sgibbs	bzero(adw->carriers, (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
129256979Sgibbs			     * sizeof(struct adw_carrier));
129356979Sgibbs
129456979Sgibbs	/* Setup our free carrier list */
129556979Sgibbs	adw->free_carriers = adw->carriers;
129656979Sgibbs	for (i = 0; i < adw->max_acbs + ADW_NUM_CARRIER_QUEUES; i++) {
129756979Sgibbs		adw->carriers[i].carr_offset =
129856979Sgibbs			carriervtobo(adw, &adw->carriers[i]);
129956979Sgibbs		adw->carriers[i].carr_ba =
130056979Sgibbs			carriervtob(adw, &adw->carriers[i]);
130156979Sgibbs		adw->carriers[i].areq_ba = 0;
130256979Sgibbs		adw->carriers[i].next_ba =
130356979Sgibbs			carriervtobo(adw, &adw->carriers[i+1]);
130456979Sgibbs	}
130556979Sgibbs	/* Terminal carrier.  Never leaves the freelist */
130656979Sgibbs	adw->carriers[i].carr_offset =
130756979Sgibbs		carriervtobo(adw, &adw->carriers[i]);
130856979Sgibbs	adw->carriers[i].carr_ba =
130956979Sgibbs		carriervtob(adw, &adw->carriers[i]);
131056979Sgibbs	adw->carriers[i].areq_ba = 0;
131156979Sgibbs	adw->carriers[i].next_ba = ~0;
131256979Sgibbs
131356979Sgibbs	adw->init_level++;
131456979Sgibbs
131556979Sgibbs	/* DMA tag for our acb structures */
1316112782Smdodd	if (bus_dma_tag_create(
1317112782Smdodd			/* parent	*/ adw->parent_dmat,
1318112782Smdodd			/* alignment	*/ 1,
1319112782Smdodd			/* boundary	*/ 0,
1320112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1321112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1322112782Smdodd			/* filter	*/ NULL,
1323112782Smdodd			/* filterarg	*/ NULL,
1324112782Smdodd			/* maxsize	*/ adw->max_acbs * sizeof(struct acb),
1325112782Smdodd			/* nsegments	*/ 1,
1326112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1327112782Smdodd			/* flags	*/ 0,
1328117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1329117126Sscottl			/* lockarg	*/ &Giant,
1330112782Smdodd			&adw->acb_dmat) != 0) {
133156979Sgibbs		return (ENOMEM);
133240024Sgibbs        }
133340024Sgibbs
133440024Sgibbs	adw->init_level++;
133540024Sgibbs
133640024Sgibbs	/* Allocation for our ccbs */
133740024Sgibbs	if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs,
133856979Sgibbs			     BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0)
133956979Sgibbs		return (ENOMEM);
134040024Sgibbs
134140024Sgibbs	adw->init_level++;
134240024Sgibbs
134340024Sgibbs	/* And permanently map them */
134440024Sgibbs	bus_dmamap_load(adw->acb_dmat, adw->acb_dmamap,
134540024Sgibbs			adw->acbs,
134640024Sgibbs			adw->max_acbs * sizeof(struct acb),
134740024Sgibbs			adwmapmem, &adw->acb_busbase, /*flags*/0);
134840024Sgibbs
134940024Sgibbs	/* Clear them out. */
135040024Sgibbs	bzero(adw->acbs, adw->max_acbs * sizeof(struct acb));
135140024Sgibbs
135240024Sgibbs	/* DMA tag for our S/G structures.  We allocate in page sized chunks */
1353112782Smdodd	if (bus_dma_tag_create(
1354112782Smdodd			/* parent	*/ adw->parent_dmat,
1355112782Smdodd			/* alignment	*/ 1,
1356112782Smdodd			/* boundary	*/ 0,
1357112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1358112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1359112782Smdodd			/* filter	*/ NULL,
1360112782Smdodd			/* filterarg	*/ NULL,
1361112782Smdodd			/* maxsize	*/ PAGE_SIZE,
1362112782Smdodd			/* nsegments	*/ 1,
1363112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1364112782Smdodd			/* flags	*/ 0,
1365117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1366117126Sscottl			/* lockarg	*/ &Giant,
1367112782Smdodd			&adw->sg_dmat) != 0) {
136856979Sgibbs		return (ENOMEM);
136940024Sgibbs        }
137040024Sgibbs
137140024Sgibbs	adw->init_level++;
137240024Sgibbs
137340024Sgibbs	/* Allocate our first batch of ccbs */
137440024Sgibbs	if (adwallocacbs(adw) == 0)
137556979Sgibbs		return (ENOMEM);
137640024Sgibbs
137756979Sgibbs	if (adw_init_chip(adw, scsicfg1) != 0)
137856979Sgibbs		return (ENXIO);
137956979Sgibbs
138056979Sgibbs	printf("Queue Depth %d\n", adw->max_acbs);
138156979Sgibbs
138240024Sgibbs	return (0);
138340024Sgibbs}
138440024Sgibbs
138540024Sgibbs/*
138640024Sgibbs * Attach all the sub-devices we can find
138740024Sgibbs */
138840024Sgibbsint
138940024Sgibbsadw_attach(struct adw_softc *adw)
139040024Sgibbs{
139140024Sgibbs	struct ccb_setasync csa;
139240024Sgibbs	struct cam_devq *devq;
139356979Sgibbs	int s;
139456979Sgibbs	int error;
139540024Sgibbs
139656979Sgibbs	error = 0;
139756979Sgibbs	s = splcam();
139856979Sgibbs	/* Hook up our interrupt handler */
139973280Smarkm	if ((error = bus_setup_intr(adw->device, adw->irq,
140073280Smarkm				    INTR_TYPE_CAM | INTR_ENTROPY, adw_intr,
140173280Smarkm				    adw, &adw->ih)) != 0) {
140256979Sgibbs		device_printf(adw->device, "bus_setup_intr() failed: %d\n",
140356979Sgibbs			      error);
140456979Sgibbs		goto fail;
140556979Sgibbs	}
140656979Sgibbs
140740024Sgibbs	/* Start the Risc processor now that we are fully configured. */
140840024Sgibbs	adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN);
140940024Sgibbs
141040024Sgibbs	/*
141140024Sgibbs	 * Create the device queue for our SIM.
141240024Sgibbs	 */
141340024Sgibbs	devq = cam_simq_alloc(adw->max_acbs);
141440024Sgibbs	if (devq == NULL)
141556979Sgibbs		return (ENOMEM);
141640024Sgibbs
141740024Sgibbs	/*
141840024Sgibbs	 * Construct our SIM entry.
141940024Sgibbs	 */
142040024Sgibbs	adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw, adw->unit,
142140024Sgibbs				 1, adw->max_acbs, devq);
142256979Sgibbs	if (adw->sim == NULL) {
142356979Sgibbs		error = ENOMEM;
142456979Sgibbs		goto fail;
142556979Sgibbs	}
142640024Sgibbs
142740024Sgibbs	/*
142840024Sgibbs	 * Register the bus.
142940024Sgibbs	 */
143040024Sgibbs	if (xpt_bus_register(adw->sim, 0) != CAM_SUCCESS) {
143140024Sgibbs		cam_sim_free(adw->sim, /*free devq*/TRUE);
143256979Sgibbs		error = ENOMEM;
143356979Sgibbs		goto fail;
143440024Sgibbs	}
143540024Sgibbs
143640024Sgibbs	if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim),
143740024Sgibbs			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
143840024Sgibbs	   == CAM_REQ_CMP) {
143940024Sgibbs		xpt_setup_ccb(&csa.ccb_h, adw->path, /*priority*/5);
144040024Sgibbs		csa.ccb_h.func_code = XPT_SASYNC_CB;
144140024Sgibbs		csa.event_enable = AC_LOST_DEVICE;
144240024Sgibbs		csa.callback = adw_async;
144340024Sgibbs		csa.callback_arg = adw;
144440024Sgibbs		xpt_action((union ccb *)&csa);
144540024Sgibbs	}
144640024Sgibbs
144756979Sgibbsfail:
144856979Sgibbs	splx(s);
144956979Sgibbs	return (error);
145040024Sgibbs}
145140024Sgibbs
145240024Sgibbsvoid
145340024Sgibbsadw_intr(void *arg)
145440024Sgibbs{
145540024Sgibbs	struct	adw_softc *adw;
145640024Sgibbs	u_int	int_stat;
145740024Sgibbs
145840024Sgibbs	adw = (struct adw_softc *)arg;
145940024Sgibbs	if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0)
146040024Sgibbs		return;
146140024Sgibbs
146240024Sgibbs	/* Reading the register clears the interrupt. */
146340024Sgibbs	int_stat = adw_inb(adw, ADW_INTR_STATUS_REG);
146440024Sgibbs
146540024Sgibbs	if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) {
146656979Sgibbs		u_int intrb_code;
146756979Sgibbs
146856979Sgibbs		/* Async Microcode Event */
146956979Sgibbs		intrb_code = adw_lram_read_8(adw, ADW_MC_INTRB_CODE);
147056979Sgibbs		switch (intrb_code) {
147156979Sgibbs		case ADW_ASYNC_CARRIER_READY_FAILURE:
147256979Sgibbs			/*
147356979Sgibbs			 * The RISC missed our update of
147456979Sgibbs			 * the commandq.
147556979Sgibbs			 */
147656979Sgibbs			if (LIST_FIRST(&adw->pending_ccbs) != NULL)
147756979Sgibbs				adw_tickle_risc(adw, ADW_TICKLE_A);
147840024Sgibbs			break;
147956979Sgibbs    		case ADW_ASYNC_SCSI_BUS_RESET_DET:
148056979Sgibbs			/*
148156979Sgibbs			 * The firmware detected a SCSI Bus reset.
148256979Sgibbs			 */
148356979Sgibbs			printf("Someone Reset the Bus\n");
148456979Sgibbs			adw_handle_bus_reset(adw, /*initiated*/FALSE);
148556979Sgibbs			break;
148656979Sgibbs		case ADW_ASYNC_RDMA_FAILURE:
148756979Sgibbs			/*
148856979Sgibbs			 * Handle RDMA failure by resetting the
148956979Sgibbs			 * SCSI Bus and chip.
149056979Sgibbs			 */
1491153072Sru#if 0 /* XXX */
149256979Sgibbs			AdvResetChipAndSB(adv_dvc_varp);
149356979Sgibbs#endif
149456979Sgibbs			break;
149556979Sgibbs
149656979Sgibbs		case ADW_ASYNC_HOST_SCSI_BUS_RESET:
149756979Sgibbs			/*
149856979Sgibbs			 * Host generated SCSI bus reset occurred.
149956979Sgibbs			 */
150040024Sgibbs			adw_handle_bus_reset(adw, /*initiated*/TRUE);
150156979Sgibbs        		break;
150256979Sgibbs    		default:
150356979Sgibbs			printf("adw_intr: unknown async code 0x%x\n",
150456979Sgibbs			       intrb_code);
150540024Sgibbs			break;
150640024Sgibbs		}
150740024Sgibbs	}
150840024Sgibbs
150940024Sgibbs	/*
151056979Sgibbs	 * Run down the RequestQ.
151140024Sgibbs	 */
151256979Sgibbs	while ((adw->responseq->next_ba & ADW_RQ_DONE) != 0) {
151356979Sgibbs		struct adw_carrier *free_carrier;
151456979Sgibbs		struct acb *acb;
151556979Sgibbs		union ccb *ccb;
151640024Sgibbs
151756979Sgibbs#if 0
151856979Sgibbs		printf("0x%x, 0x%x, 0x%x, 0x%x\n",
151956979Sgibbs		       adw->responseq->carr_offset,
152056979Sgibbs		       adw->responseq->carr_ba,
152156979Sgibbs		       adw->responseq->areq_ba,
152256979Sgibbs		       adw->responseq->next_ba);
152356979Sgibbs#endif
152456979Sgibbs		/*
152556979Sgibbs		 * The firmware copies the adw_scsi_req_q.acb_baddr
152656979Sgibbs		 * field into the areq_ba field of the carrier.
152756979Sgibbs		 */
152856979Sgibbs		acb = acbbotov(adw, adw->responseq->areq_ba);
152940024Sgibbs
153040024Sgibbs		/*
153156979Sgibbs		 * The least significant four bits of the next_ba
153256979Sgibbs		 * field are used as flags.  Mask them out and then
153356979Sgibbs		 * advance through the list.
153440024Sgibbs		 */
153556979Sgibbs		free_carrier = adw->responseq;
153656979Sgibbs		adw->responseq =
153756979Sgibbs		    carrierbotov(adw, free_carrier->next_ba & ADW_NEXT_BA_MASK);
153856979Sgibbs		free_carrier->next_ba = adw->free_carriers->carr_offset;
153956979Sgibbs		adw->free_carriers = free_carrier;
154040024Sgibbs
154140024Sgibbs		/* Process CCB */
154240024Sgibbs		ccb = acb->ccb;
154340024Sgibbs		untimeout(adwtimeout, acb, ccb->ccb_h.timeout_ch);
154440024Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
1545115343Sscottl			bus_dmasync_op_t op;
154640024Sgibbs
154740024Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
154840024Sgibbs				op = BUS_DMASYNC_POSTREAD;
154940024Sgibbs			else
155040024Sgibbs				op = BUS_DMASYNC_POSTWRITE;
155140024Sgibbs			bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
155240024Sgibbs			bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
155340024Sgibbs			ccb->csio.resid = acb->queue.data_cnt;
155440024Sgibbs		} else
155540024Sgibbs			ccb->csio.resid = 0;
155640024Sgibbs
155740024Sgibbs		/* Common Cases inline... */
155840024Sgibbs		if (acb->queue.host_status == QHSTA_NO_ERROR
155940024Sgibbs		 && (acb->queue.done_status == QD_NO_ERROR
156040024Sgibbs		  || acb->queue.done_status == QD_WITH_ERROR)) {
156140024Sgibbs			ccb->csio.scsi_status = acb->queue.scsi_status;
156240024Sgibbs			ccb->ccb_h.status = 0;
156340024Sgibbs			switch (ccb->csio.scsi_status) {
156440024Sgibbs			case SCSI_STATUS_OK:
156540024Sgibbs				ccb->ccb_h.status |= CAM_REQ_CMP;
156640024Sgibbs				break;
156740024Sgibbs			case SCSI_STATUS_CHECK_COND:
156840024Sgibbs			case SCSI_STATUS_CMD_TERMINATED:
156940024Sgibbs				bcopy(&acb->sense_data, &ccb->csio.sense_data,
157040024Sgibbs				      ccb->csio.sense_len);
157140024Sgibbs				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
157240024Sgibbs				ccb->csio.sense_resid = acb->queue.sense_len;
157340024Sgibbs				/* FALLTHROUGH */
157440024Sgibbs			default:
157540024Sgibbs				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR
157640024Sgibbs						  |  CAM_DEV_QFRZN;
157740024Sgibbs				xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
157840024Sgibbs				break;
157940024Sgibbs			}
158040024Sgibbs			adwfreeacb(adw, acb);
158140024Sgibbs			xpt_done(ccb);
158240024Sgibbs		} else {
158340024Sgibbs			adwprocesserror(adw, acb);
158440024Sgibbs		}
158540024Sgibbs	}
158640024Sgibbs}
158740024Sgibbs
158840024Sgibbsstatic void
158940024Sgibbsadwprocesserror(struct adw_softc *adw, struct acb *acb)
159040024Sgibbs{
159140024Sgibbs	union ccb *ccb;
159240024Sgibbs
159340024Sgibbs	ccb = acb->ccb;
159440024Sgibbs	if (acb->queue.done_status == QD_ABORTED_BY_HOST) {
159540024Sgibbs		ccb->ccb_h.status = CAM_REQ_ABORTED;
159640024Sgibbs	} else {
159740024Sgibbs
159840024Sgibbs		switch (acb->queue.host_status) {
159940024Sgibbs		case QHSTA_M_SEL_TIMEOUT:
160040024Sgibbs			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
160140024Sgibbs			break;
160240024Sgibbs		case QHSTA_M_SXFR_OFF_UFLW:
160340024Sgibbs		case QHSTA_M_SXFR_OFF_OFLW:
160440024Sgibbs		case QHSTA_M_DATA_OVER_RUN:
160540024Sgibbs			ccb->ccb_h.status = CAM_DATA_RUN_ERR;
160640024Sgibbs			break;
160740024Sgibbs		case QHSTA_M_SXFR_DESELECTED:
160840024Sgibbs		case QHSTA_M_UNEXPECTED_BUS_FREE:
160940024Sgibbs			ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
161040024Sgibbs			break;
161157679Sgibbs		case QHSTA_M_SCSI_BUS_RESET:
161257679Sgibbs		case QHSTA_M_SCSI_BUS_RESET_UNSOL:
161357679Sgibbs			ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
161457679Sgibbs			break;
161557679Sgibbs		case QHSTA_M_BUS_DEVICE_RESET:
161657679Sgibbs			ccb->ccb_h.status = CAM_BDR_SENT;
161757679Sgibbs			break;
161840024Sgibbs		case QHSTA_M_QUEUE_ABORTED:
161940024Sgibbs			/* BDR or Bus Reset */
162057679Sgibbs			printf("Saw Queue Aborted\n");
162140024Sgibbs			ccb->ccb_h.status = adw->last_reset;
162240024Sgibbs			break;
162340024Sgibbs		case QHSTA_M_SXFR_SDMA_ERR:
162440024Sgibbs		case QHSTA_M_SXFR_SXFR_PERR:
162540024Sgibbs		case QHSTA_M_RDMA_PERR:
162640024Sgibbs			ccb->ccb_h.status = CAM_UNCOR_PARITY;
162740024Sgibbs			break;
162840024Sgibbs		case QHSTA_M_WTM_TIMEOUT:
162940024Sgibbs		case QHSTA_M_SXFR_WD_TMO:
163056979Sgibbs		{
163140024Sgibbs			/* The SCSI bus hung in a phase */
163257679Sgibbs			xpt_print_path(adw->path);
163357679Sgibbs			printf("Watch Dog timer expired.  Reseting bus\n");
163457679Sgibbs			adw_reset_bus(adw);
163540024Sgibbs			break;
163656979Sgibbs		}
163740024Sgibbs		case QHSTA_M_SXFR_XFR_PH_ERR:
163840024Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
163940024Sgibbs			break;
164040024Sgibbs		case QHSTA_M_SXFR_UNKNOWN_ERROR:
164140024Sgibbs			break;
164240024Sgibbs		case QHSTA_M_BAD_CMPL_STATUS_IN:
164340024Sgibbs			/* No command complete after a status message */
164440024Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
164540024Sgibbs			break;
164640024Sgibbs		case QHSTA_M_AUTO_REQ_SENSE_FAIL:
164740024Sgibbs			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
164840024Sgibbs			break;
164940024Sgibbs		case QHSTA_M_INVALID_DEVICE:
165040024Sgibbs			ccb->ccb_h.status = CAM_PATH_INVALID;
165140024Sgibbs			break;
165240024Sgibbs		case QHSTA_M_NO_AUTO_REQ_SENSE:
165340024Sgibbs			/*
165440024Sgibbs			 * User didn't request sense, but we got a
165540024Sgibbs			 * check condition.
165640024Sgibbs			 */
165740024Sgibbs			ccb->csio.scsi_status = acb->queue.scsi_status;
165840024Sgibbs			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
165940024Sgibbs			break;
166040024Sgibbs		default:
166140024Sgibbs			panic("%s: Unhandled Host status error %x",
166240024Sgibbs			      adw_name(adw), acb->queue.host_status);
166340024Sgibbs			/* NOTREACHED */
166440024Sgibbs		}
166540024Sgibbs	}
166657679Sgibbs	if ((acb->state & ACB_RECOVERY_ACB) != 0) {
166757679Sgibbs		if (ccb->ccb_h.status == CAM_SCSI_BUS_RESET
166857679Sgibbs		 || ccb->ccb_h.status == CAM_BDR_SENT)
166957679Sgibbs		 	ccb->ccb_h.status = CAM_CMD_TIMEOUT;
167057679Sgibbs	}
167140024Sgibbs	if (ccb->ccb_h.status != CAM_REQ_CMP) {
167240024Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
167340024Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
167440024Sgibbs	}
167540024Sgibbs	adwfreeacb(adw, acb);
167640024Sgibbs	xpt_done(ccb);
167740024Sgibbs}
167840024Sgibbs
167940024Sgibbsstatic void
168040024Sgibbsadwtimeout(void *arg)
168140024Sgibbs{
168240024Sgibbs	struct acb	     *acb;
168340024Sgibbs	union  ccb	     *ccb;
168440024Sgibbs	struct adw_softc     *adw;
168540024Sgibbs	adw_idle_cmd_status_t status;
168657679Sgibbs	int		      target_id;
168740024Sgibbs	int		      s;
168840024Sgibbs
168940024Sgibbs	acb = (struct acb *)arg;
169040024Sgibbs	ccb = acb->ccb;
169140024Sgibbs	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
169240024Sgibbs	xpt_print_path(ccb->ccb_h.path);
169340024Sgibbs	printf("ACB %p - timed out\n", (void *)acb);
169440024Sgibbs
169540024Sgibbs	s = splcam();
169640024Sgibbs
169740024Sgibbs	if ((acb->state & ACB_ACTIVE) == 0) {
169840024Sgibbs		xpt_print_path(ccb->ccb_h.path);
169940024Sgibbs		printf("ACB %p - timed out CCB already completed\n",
170040024Sgibbs		       (void *)acb);
170140024Sgibbs		splx(s);
170240024Sgibbs		return;
170340024Sgibbs	}
170440024Sgibbs
170557679Sgibbs	acb->state |= ACB_RECOVERY_ACB;
170657679Sgibbs	target_id = ccb->ccb_h.target_id;
170757679Sgibbs
170840024Sgibbs	/* Attempt a BDR first */
170957679Sgibbs	status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
171057679Sgibbs				   ccb->ccb_h.target_id);
171140024Sgibbs	splx(s);
171240024Sgibbs	if (status == ADW_IDLE_CMD_SUCCESS) {
171340024Sgibbs		printf("%s: BDR Delivered.  No longer in timeout\n",
171440024Sgibbs		       adw_name(adw));
171557679Sgibbs		adw_handle_device_reset(adw, target_id);
171640024Sgibbs	} else {
171757679Sgibbs		adw_reset_bus(adw);
171857679Sgibbs		xpt_print_path(adw->path);
171957679Sgibbs		printf("Bus Reset Delivered.  No longer in timeout\n");
172040024Sgibbs	}
172140024Sgibbs}
172240024Sgibbs
172340024Sgibbsstatic void
172440024Sgibbsadw_handle_device_reset(struct adw_softc *adw, u_int target)
172540024Sgibbs{
172640024Sgibbs	struct cam_path *path;
172740024Sgibbs	cam_status error;
172840024Sgibbs
172940024Sgibbs	error = xpt_create_path(&path, /*periph*/NULL, cam_sim_path(adw->sim),
173040024Sgibbs				target, CAM_LUN_WILDCARD);
173140024Sgibbs
173240024Sgibbs	if (error == CAM_REQ_CMP) {
173340024Sgibbs		xpt_async(AC_SENT_BDR, path, NULL);
173440024Sgibbs		xpt_free_path(path);
173540024Sgibbs	}
173640024Sgibbs	adw->last_reset = CAM_BDR_SENT;
173740024Sgibbs}
173840024Sgibbs
173940024Sgibbsstatic void
174040024Sgibbsadw_handle_bus_reset(struct adw_softc *adw, int initiated)
174140024Sgibbs{
174240024Sgibbs	if (initiated) {
174340024Sgibbs		/*
174440024Sgibbs		 * The microcode currently sets the SCSI Bus Reset signal
174540024Sgibbs		 * while handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET
174640024Sgibbs		 * command above.  But the SCSI Bus Reset Hold Time in the
174740024Sgibbs		 * microcode is not deterministic (it may in fact be for less
174840024Sgibbs		 * than the SCSI Spec. minimum of 25 us).  Therefore on return
174940024Sgibbs		 * the Adv Library sets the SCSI Bus Reset signal for
175040024Sgibbs		 * ADW_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
175140024Sgibbs		 * than 25 us.
175240024Sgibbs		 */
175340024Sgibbs		u_int scsi_ctrl;
175440024Sgibbs
175540024Sgibbs	    	scsi_ctrl = adw_inw(adw, ADW_SCSI_CTRL) & ~ADW_SCSI_CTRL_RSTOUT;
175640024Sgibbs		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl | ADW_SCSI_CTRL_RSTOUT);
175740024Sgibbs		DELAY(ADW_SCSI_RESET_HOLD_TIME_US);
175840024Sgibbs		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl);
175940024Sgibbs
176040024Sgibbs		/*
176140024Sgibbs		 * We will perform the async notification when the
176240024Sgibbs		 * SCSI Reset interrupt occurs.
176340024Sgibbs		 */
176440024Sgibbs	} else
176540024Sgibbs		xpt_async(AC_BUS_RESET, adw->path, NULL);
176640024Sgibbs	adw->last_reset = CAM_SCSI_BUS_RESET;
176740024Sgibbs}
1768