adwcam.c revision 46581
140024Sgibbs/*
240024Sgibbs * CAM SCSI interface for the the Advanced Systems Inc.
340024Sgibbs * Second Generation SCSI controllers.
440024Sgibbs *
540024Sgibbs * Product specific probe and attach routines can be found in:
640024Sgibbs *
740024Sgibbs * pci/adw_pci.c	ABP940UW
840024Sgibbs *
940024Sgibbs * Copyright (c) 1998 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,
1740024Sgibbs *    without modification, immediately at the beginning of the file.
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 *
3346581Sken *      $Id: adwcam.c,v 1.2 1998/10/15 23:47:14 gibbs Exp $
3440024Sgibbs */
3540024Sgibbs/*
3640024Sgibbs * Ported from:
3740024Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
3840024Sgibbs *
3940024Sgibbs * Copyright (c) 1995-1998 Advanced System Products, Inc.
4040024Sgibbs * All Rights Reserved.
4140024Sgibbs *
4240024Sgibbs * Redistribution and use in source and binary forms, with or without
4340024Sgibbs * modification, are permitted provided that redistributions of source
4440024Sgibbs * code retain the above copyright notice and this comment without
4540024Sgibbs * modification.
4640024Sgibbs */
4740024Sgibbs#include <stddef.h>	/* For offsetof */
4840024Sgibbs
4940024Sgibbs#include <sys/param.h>
5040024Sgibbs#include <sys/systm.h>
5140024Sgibbs#include <sys/kernel.h>
5240024Sgibbs#include <sys/malloc.h>
5340024Sgibbs
5440024Sgibbs#include <machine/bus_pio.h>
5540024Sgibbs#include <machine/bus_memio.h>
5640024Sgibbs#include <machine/bus.h>
5740024Sgibbs#include <machine/clock.h>
5840024Sgibbs
5940024Sgibbs#include <cam/cam.h>
6040024Sgibbs#include <cam/cam_ccb.h>
6140024Sgibbs#include <cam/cam_sim.h>
6240024Sgibbs#include <cam/cam_xpt_sim.h>
6340024Sgibbs#include <cam/cam_debug.h>
6440024Sgibbs
6540024Sgibbs#include <cam/scsi/scsi_message.h>
6640024Sgibbs
6740024Sgibbs#include <dev/advansys/adwvar.h>
6840024Sgibbs
6940024Sgibbs/* Definitions for our use of the SIM private CCB area */
7040024Sgibbs#define ccb_acb_ptr spriv_ptr0
7140024Sgibbs#define ccb_adw_ptr spriv_ptr1
7240024Sgibbs
7340024Sgibbs#define MIN(a, b) (((a) < (b)) ? (a) : (b))
7440024Sgibbs
7540024Sgibbsu_long adw_unit;
7640024Sgibbs
7740024Sgibbsstatic __inline u_int32_t	acbvtop(struct adw_softc *adw,
7840024Sgibbs					   struct acb *acb);
7940024Sgibbsstatic __inline struct acb *	acbptov(struct adw_softc *adw,
8040024Sgibbs					u_int32_t busaddr);
8140024Sgibbsstatic __inline struct acb*	adwgetacb(struct adw_softc *adw);
8240024Sgibbsstatic __inline void		adwfreeacb(struct adw_softc *adw,
8340024Sgibbs					   struct acb *acb);
8440024Sgibbs
8540024Sgibbsstatic void		adwmapmem(void *arg, bus_dma_segment_t *segs,
8640024Sgibbs				  int nseg, int error);
8740024Sgibbsstatic struct sg_map_node*
8840024Sgibbs			adwallocsgmap(struct adw_softc *adw);
8940024Sgibbsstatic int		adwallocacbs(struct adw_softc *adw);
9040024Sgibbs
9140024Sgibbsstatic void		adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs,
9240024Sgibbs				      int nseg, int error);
9340024Sgibbsstatic void		adw_action(struct cam_sim *sim, union ccb *ccb);
9440024Sgibbsstatic void		adw_poll(struct cam_sim *sim);
9540024Sgibbsstatic void		adw_async(void *callback_arg, u_int32_t code,
9640024Sgibbs				  struct cam_path *path, void *arg);
9740024Sgibbsstatic void		adwprocesserror(struct adw_softc *adw, struct acb *acb);
9840024Sgibbsstatic void		adwtimeout(void *arg);
9940024Sgibbsstatic void		adw_handle_device_reset(struct adw_softc *adw,
10040024Sgibbs						u_int target);
10140024Sgibbsstatic void		adw_handle_bus_reset(struct adw_softc *adw,
10240024Sgibbs					     int initiated);
10340024Sgibbs
10440024Sgibbsstatic __inline u_int32_t
10540024Sgibbsacbvtop(struct adw_softc *adw, struct acb *acb)
10640024Sgibbs{
10740024Sgibbs	return (adw->acb_busbase
10840024Sgibbs	      + (u_int32_t)((caddr_t)acb - (caddr_t)adw->acbs));
10940024Sgibbs}
11040024Sgibbs
11140024Sgibbsstatic __inline struct acb *
11240024Sgibbsacbptov(struct adw_softc *adw, u_int32_t busaddr)
11340024Sgibbs{
11440024Sgibbs	return (adw->acbs
11540024Sgibbs	      + ((struct acb *)busaddr - (struct acb *)adw->acb_busbase));
11640024Sgibbs}
11740024Sgibbs
11840024Sgibbsstatic __inline struct acb*
11940024Sgibbsadwgetacb(struct adw_softc *adw)
12040024Sgibbs{
12140024Sgibbs	struct	acb* acb;
12240024Sgibbs	int	s;
12340024Sgibbs
12440024Sgibbs	s = splcam();
12540024Sgibbs	if ((acb = SLIST_FIRST(&adw->free_acb_list)) != NULL) {
12640024Sgibbs		SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
12740024Sgibbs	} else if (adw->num_acbs < adw->max_acbs) {
12840024Sgibbs		adwallocacbs(adw);
12940024Sgibbs		acb = SLIST_FIRST(&adw->free_acb_list);
13040024Sgibbs		if (acb == NULL)
13140024Sgibbs			printf("%s: Can't malloc ACB\n", adw_name(adw));
13240024Sgibbs		else {
13340024Sgibbs			SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
13440024Sgibbs		}
13540024Sgibbs	}
13640024Sgibbs	splx(s);
13740024Sgibbs
13840024Sgibbs	return (acb);
13940024Sgibbs}
14040024Sgibbs
14140024Sgibbsstatic __inline void
14240024Sgibbsadwfreeacb(struct adw_softc *adw, struct acb *acb)
14340024Sgibbs{
14440024Sgibbs	int s;
14540024Sgibbs
14640024Sgibbs	s = splcam();
14740024Sgibbs	if ((acb->state & ACB_ACTIVE) != 0)
14840024Sgibbs		LIST_REMOVE(&acb->ccb->ccb_h, sim_links.le);
14940024Sgibbs	if ((acb->state & ACB_RELEASE_SIMQ) != 0)
15040024Sgibbs		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
15140024Sgibbs	else if ((adw->state & ADW_RESOURCE_SHORTAGE) != 0
15240024Sgibbs	      && (acb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
15340024Sgibbs		acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
15440024Sgibbs		adw->state &= ~ADW_RESOURCE_SHORTAGE;
15540024Sgibbs	}
15640024Sgibbs	acb->state = ACB_FREE;
15740024Sgibbs	SLIST_INSERT_HEAD(&adw->free_acb_list, acb, links);
15840024Sgibbs	splx(s);
15940024Sgibbs}
16040024Sgibbs
16140024Sgibbsstatic void
16240024Sgibbsadwmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
16340024Sgibbs{
16440024Sgibbs	bus_addr_t *busaddrp;
16540024Sgibbs
16640024Sgibbs	busaddrp = (bus_addr_t *)arg;
16740024Sgibbs	*busaddrp = segs->ds_addr;
16840024Sgibbs}
16940024Sgibbs
17040024Sgibbsstatic struct sg_map_node *
17140024Sgibbsadwallocsgmap(struct adw_softc *adw)
17240024Sgibbs{
17340024Sgibbs	struct sg_map_node *sg_map;
17440024Sgibbs
17540024Sgibbs	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
17640024Sgibbs
17740024Sgibbs	if (sg_map == NULL)
17840024Sgibbs		return (NULL);
17940024Sgibbs
18040024Sgibbs	/* Allocate S/G space for the next batch of ACBS */
18140024Sgibbs	if (bus_dmamem_alloc(adw->sg_dmat, (void **)&sg_map->sg_vaddr,
18240024Sgibbs			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
18340024Sgibbs		free(sg_map, M_DEVBUF);
18440024Sgibbs		return (NULL);
18540024Sgibbs	}
18640024Sgibbs
18740024Sgibbs	SLIST_INSERT_HEAD(&adw->sg_maps, sg_map, links);
18840024Sgibbs
18940024Sgibbs	bus_dmamap_load(adw->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
19040024Sgibbs			PAGE_SIZE, adwmapmem, &sg_map->sg_physaddr, /*flags*/0);
19140024Sgibbs
19240024Sgibbs	bzero(sg_map->sg_vaddr, PAGE_SIZE);
19340024Sgibbs	return (sg_map);
19440024Sgibbs}
19540024Sgibbs
19640024Sgibbs/*
19740024Sgibbs * Allocate another chunk of CCB's. Return count of entries added.
19840024Sgibbs * Assumed to be called at splcam().
19940024Sgibbs */
20040024Sgibbsstatic int
20140024Sgibbsadwallocacbs(struct adw_softc *adw)
20240024Sgibbs{
20340024Sgibbs	struct acb *next_acb;
20440024Sgibbs	struct sg_map_node *sg_map;
20540024Sgibbs	bus_addr_t busaddr;
20640024Sgibbs	struct adw_sg_block *blocks;
20740024Sgibbs	int newcount;
20840024Sgibbs	int i;
20940024Sgibbs
21040024Sgibbs	next_acb = &adw->acbs[adw->num_acbs];
21140024Sgibbs
21240024Sgibbs	sg_map = adwallocsgmap(adw);
21340024Sgibbs
21440024Sgibbs	if (sg_map == NULL)
21540024Sgibbs		return (0);
21640024Sgibbs
21740024Sgibbs	blocks = sg_map->sg_vaddr;
21840024Sgibbs	busaddr = sg_map->sg_physaddr;
21940024Sgibbs
22040024Sgibbs	newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks)));
22140024Sgibbs	for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) {
22240024Sgibbs		int error;
22340024Sgibbs		int j;
22440024Sgibbs
22540024Sgibbs		error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0,
22640024Sgibbs					  &next_acb->dmamap);
22740024Sgibbs		if (error != 0)
22840024Sgibbs			break;
22940024Sgibbs		next_acb->queue.scsi_req_baddr = acbvtop(adw, next_acb);
23040024Sgibbs		next_acb->queue.sense_addr =
23140024Sgibbs		    acbvtop(adw, next_acb) + offsetof(struct acb, sense_data);
23240024Sgibbs		next_acb->sg_blocks = blocks;
23340024Sgibbs		next_acb->sg_busaddr = busaddr;
23440024Sgibbs		/* Setup static data in the sg blocks */
23540024Sgibbs		for (j = 0; j < ADW_SG_BLOCKCNT; j++) {
23640024Sgibbs			next_acb->sg_blocks[j].first_entry_no =
23740024Sgibbs			    j * ADW_NO_OF_SG_PER_BLOCK;
23840024Sgibbs		}
23940024Sgibbs		next_acb->state = ACB_FREE;
24040024Sgibbs		SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links);
24140024Sgibbs		blocks += ADW_SG_BLOCKCNT;
24240024Sgibbs		busaddr += ADW_SG_BLOCKCNT * sizeof(*blocks);
24340024Sgibbs		next_acb++;
24440024Sgibbs		adw->num_acbs++;
24540024Sgibbs	}
24640024Sgibbs	return (i);
24740024Sgibbs}
24840024Sgibbs
24940024Sgibbsstatic void
25040024Sgibbsadwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
25140024Sgibbs{
25240024Sgibbs	struct	 acb *acb;
25340024Sgibbs	union	 ccb *ccb;
25440024Sgibbs	struct	 adw_softc *adw;
25540420Sgibbs	int	 s;
25640024Sgibbs
25740024Sgibbs	acb = (struct acb *)arg;
25840024Sgibbs	ccb = acb->ccb;
25940024Sgibbs	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
26040024Sgibbs
26140024Sgibbs	if (error != 0) {
26240024Sgibbs		if (error != EFBIG)
26340024Sgibbs			printf("%s: Unexepected error 0x%x returned from "
26440024Sgibbs			       "bus_dmamap_load\n", adw_name(adw), error);
26540024Sgibbs		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
26640024Sgibbs			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
26740024Sgibbs			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
26840024Sgibbs		}
26940024Sgibbs		adwfreeacb(adw, acb);
27040024Sgibbs		xpt_done(ccb);
27140024Sgibbs		return;
27240024Sgibbs	}
27340024Sgibbs
27440024Sgibbs	if (nseg != 0) {
27540024Sgibbs		bus_dmasync_op_t op;
27640024Sgibbs
27740024Sgibbs		acb->queue.data_addr = dm_segs[0].ds_addr;
27840024Sgibbs		acb->queue.data_cnt = ccb->csio.dxfer_len;
27940024Sgibbs		if (nseg > 1) {
28040024Sgibbs			struct adw_sg_block *sg_block;
28140024Sgibbs			struct adw_sg_elm *sg;
28240024Sgibbs			bus_addr_t sg_busaddr;
28340024Sgibbs			u_int sg_index;
28440024Sgibbs			bus_dma_segment_t *end_seg;
28540024Sgibbs
28640024Sgibbs			end_seg = dm_segs + nseg;
28740024Sgibbs
28840024Sgibbs			sg_busaddr = acb->sg_busaddr;
28940024Sgibbs			sg_index = 0;
29040024Sgibbs			/* Copy the segments into our SG list */
29140024Sgibbs			for (sg_block = acb->sg_blocks;; sg_block++) {
29240024Sgibbs				u_int sg_left;
29340024Sgibbs
29440024Sgibbs				sg_left = ADW_NO_OF_SG_PER_BLOCK;
29540024Sgibbs				sg = sg_block->sg_list;
29640024Sgibbs				while (dm_segs < end_seg && sg_left != 0) {
29740024Sgibbs					sg->sg_addr = dm_segs->ds_addr;
29840024Sgibbs					sg->sg_count = dm_segs->ds_len;
29940024Sgibbs					sg++;
30040024Sgibbs					dm_segs++;
30140024Sgibbs					sg_left--;
30240024Sgibbs				}
30340024Sgibbs				sg_index += ADW_NO_OF_SG_PER_BLOCK - sg_left;
30440024Sgibbs				sg_block->last_entry_no = sg_index - 1;
30540024Sgibbs				if (dm_segs == end_seg) {
30640024Sgibbs					sg_block->sg_busaddr_next = 0;
30740024Sgibbs					break;
30840024Sgibbs				} else {
30940024Sgibbs					sg_busaddr +=
31040024Sgibbs					    sizeof(struct adw_sg_block);
31140024Sgibbs					sg_block->sg_busaddr_next = sg_busaddr;
31240024Sgibbs				}
31340024Sgibbs			}
31440024Sgibbs
31540024Sgibbs			acb->queue.sg_entry_cnt = nseg;
31640024Sgibbs			acb->queue.sg_real_addr = acb->sg_busaddr;
31740024Sgibbs		} else {
31840024Sgibbs			acb->queue.sg_entry_cnt = 0;
31940024Sgibbs			acb->queue.sg_real_addr = 0;
32040024Sgibbs		}
32140024Sgibbs
32240024Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
32340024Sgibbs			op = BUS_DMASYNC_PREREAD;
32440024Sgibbs		else
32540024Sgibbs			op = BUS_DMASYNC_PREWRITE;
32640024Sgibbs
32740024Sgibbs		bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
32840024Sgibbs
32940024Sgibbs	} else {
33040024Sgibbs		acb->queue.sg_entry_cnt = 0;
33140024Sgibbs		acb->queue.data_addr = 0;
33240024Sgibbs		acb->queue.data_cnt = 0;
33340024Sgibbs		acb->queue.sg_real_addr = 0;
33440024Sgibbs	}
33540024Sgibbs	acb->queue.free_scsiq_link = 0;
33640024Sgibbs	acb->queue.ux_wk_data_cnt = 0;
33740024Sgibbs
33840024Sgibbs	s = splcam();
33940024Sgibbs
34040024Sgibbs	/*
34140024Sgibbs	 * Last time we need to check if this CCB needs to
34240024Sgibbs	 * be aborted.
34340024Sgibbs	 */
34440024Sgibbs	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
34540024Sgibbs		if (nseg != 0)
34640024Sgibbs			bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
34740024Sgibbs		adwfreeacb(adw, acb);
34840024Sgibbs		xpt_done(ccb);
34940024Sgibbs		splx(s);
35040024Sgibbs		return;
35140024Sgibbs	}
35240024Sgibbs
35340024Sgibbs	acb->state |= ACB_ACTIVE;
35440024Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
35540024Sgibbs	LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le);
35640024Sgibbs	ccb->ccb_h.timeout_ch =
35740024Sgibbs	    timeout(adwtimeout, (caddr_t)acb,
35840024Sgibbs		    (ccb->ccb_h.timeout * hz) / 1000);
35940024Sgibbs
36040024Sgibbs	adw_send_acb(adw, acb, acbvtop(adw, acb));
36140024Sgibbs
36240024Sgibbs	splx(s);
36340024Sgibbs}
36440024Sgibbs
36540024Sgibbsstatic void
36640024Sgibbsadw_action(struct cam_sim *sim, union ccb *ccb)
36740024Sgibbs{
36840024Sgibbs	struct	adw_softc *adw;
36940024Sgibbs
37040024Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adw_action\n"));
37140024Sgibbs
37240024Sgibbs	adw = (struct adw_softc *)cam_sim_softc(sim);
37340024Sgibbs
37440024Sgibbs	switch (ccb->ccb_h.func_code) {
37540024Sgibbs	/* Common cases first */
37640024Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
37740024Sgibbs	{
37840024Sgibbs		struct	ccb_scsiio *csio;
37940024Sgibbs		struct	ccb_hdr *ccbh;
38040024Sgibbs		struct	acb *acb;
38140024Sgibbs
38240024Sgibbs		csio = &ccb->csio;
38340024Sgibbs		ccbh = &ccb->ccb_h;
38440024Sgibbs		/* Max supported CDB length is 12 bytes */
38540024Sgibbs		if (csio->cdb_len > 12) {
38640024Sgibbs			ccb->ccb_h.status = CAM_REQ_INVALID;
38740024Sgibbs			xpt_done(ccb);
38840024Sgibbs			return;
38940024Sgibbs		}
39040024Sgibbs
39140024Sgibbs		if ((acb = adwgetacb(adw)) == NULL) {
39240024Sgibbs			int s;
39340024Sgibbs
39440024Sgibbs			s = splcam();
39540024Sgibbs			adw->state |= ADW_RESOURCE_SHORTAGE;
39640024Sgibbs			splx(s);
39740024Sgibbs			xpt_freeze_simq(sim, /*count*/1);
39840024Sgibbs			ccb->ccb_h.status = CAM_REQUEUE_REQ;
39940024Sgibbs			xpt_done(ccb);
40040024Sgibbs			return;
40140024Sgibbs		}
40240024Sgibbs
40340024Sgibbs		/* Link dccb and ccb so we can find one from the other */
40440024Sgibbs		acb->ccb = ccb;
40540024Sgibbs		ccb->ccb_h.ccb_acb_ptr = acb;
40640024Sgibbs		ccb->ccb_h.ccb_adw_ptr = adw;
40740024Sgibbs
40840024Sgibbs		acb->queue.cntl = 0;
40940024Sgibbs		acb->queue.target_id = ccb->ccb_h.target_id;
41040024Sgibbs		acb->queue.target_lun = ccb->ccb_h.target_lun;
41140024Sgibbs
41240024Sgibbs		acb->queue.srb_ptr = 0;
41340024Sgibbs		acb->queue.a_flag = 0;
41440024Sgibbs		acb->queue.sense_len =
41540024Sgibbs			MIN(csio->sense_len, sizeof(acb->sense_data));
41640024Sgibbs		acb->queue.cdb_len = csio->cdb_len;
41740024Sgibbs
41840024Sgibbs		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0)
41940024Sgibbs			acb->queue.tag_code = csio->tag_action;
42040024Sgibbs		else
42140024Sgibbs			acb->queue.tag_code = 0;
42240024Sgibbs
42340024Sgibbs		acb->queue.done_status = 0;
42440024Sgibbs		acb->queue.scsi_status = 0;
42540024Sgibbs		acb->queue.host_status = 0;
42640024Sgibbs		acb->queue.ux_sg_ix = 0;
42740024Sgibbs
42840024Sgibbs		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
42940024Sgibbs			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
43040024Sgibbs				bcopy(csio->cdb_io.cdb_ptr,
43140024Sgibbs				      acb->queue.cdb, csio->cdb_len);
43240024Sgibbs			} else {
43340024Sgibbs				/* I guess I could map it in... */
43440024Sgibbs				ccb->ccb_h.status = CAM_REQ_INVALID;
43540024Sgibbs				adwfreeacb(adw, acb);
43640024Sgibbs				xpt_done(ccb);
43740024Sgibbs				return;
43840024Sgibbs			}
43940024Sgibbs		} else {
44040024Sgibbs			bcopy(csio->cdb_io.cdb_bytes,
44140024Sgibbs			      acb->queue.cdb, csio->cdb_len);
44240024Sgibbs		}
44340024Sgibbs
44440024Sgibbs		/*
44540024Sgibbs		 * If we have any data to send with this command,
44640024Sgibbs		 * map it into bus space.
44740024Sgibbs		 */
44840024Sgibbs		if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
44940024Sgibbs			if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
45040024Sgibbs				/*
45140024Sgibbs				 * We've been given a pointer
45240024Sgibbs				 * to a single buffer.
45340024Sgibbs				 */
45440024Sgibbs				if ((ccbh->flags & CAM_DATA_PHYS) == 0) {
45540024Sgibbs					int s;
45640024Sgibbs					int error;
45740024Sgibbs
45840024Sgibbs					s = splsoftvm();
45940024Sgibbs					error =
46040024Sgibbs					    bus_dmamap_load(adw->buffer_dmat,
46140024Sgibbs							    acb->dmamap,
46240024Sgibbs							    csio->data_ptr,
46340024Sgibbs							    csio->dxfer_len,
46440024Sgibbs							    adwexecuteacb,
46540024Sgibbs							    acb, /*flags*/0);
46640024Sgibbs					if (error == EINPROGRESS) {
46740024Sgibbs						/*
46840024Sgibbs						 * So as to maintain ordering,
46940024Sgibbs						 * freeze the controller queue
47040024Sgibbs						 * until our mapping is
47140024Sgibbs						 * returned.
47240024Sgibbs						 */
47340024Sgibbs						xpt_freeze_simq(sim, 1);
47440024Sgibbs						acb->state |= CAM_RELEASE_SIMQ;
47540024Sgibbs					}
47640024Sgibbs					splx(s);
47740024Sgibbs				} else {
47840024Sgibbs					struct bus_dma_segment seg;
47940024Sgibbs
48040024Sgibbs					/* Pointer to physical buffer */
48140024Sgibbs					seg.ds_addr =
48240024Sgibbs					    (bus_addr_t)csio->data_ptr;
48340024Sgibbs					seg.ds_len = csio->dxfer_len;
48440024Sgibbs					adwexecuteacb(acb, &seg, 1, 0);
48540024Sgibbs				}
48640024Sgibbs			} else {
48740024Sgibbs				struct bus_dma_segment *segs;
48840024Sgibbs
48940024Sgibbs				if ((ccbh->flags & CAM_DATA_PHYS) != 0)
49040024Sgibbs					panic("adw_action - Physical "
49140024Sgibbs					      "segment pointers "
49240024Sgibbs					      "unsupported");
49340024Sgibbs
49440024Sgibbs				if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
49540024Sgibbs					panic("adw_action - Virtual "
49640024Sgibbs					      "segment addresses "
49740024Sgibbs					      "unsupported");
49840024Sgibbs
49940024Sgibbs				/* Just use the segments provided */
50040024Sgibbs				segs = (struct bus_dma_segment *)csio->data_ptr;
50140024Sgibbs				adwexecuteacb(acb, segs, csio->sglist_cnt,
50240024Sgibbs					      (csio->sglist_cnt < ADW_SGSIZE)
50340024Sgibbs					      ? 0 : EFBIG);
50440024Sgibbs			}
50540024Sgibbs		} else {
50640024Sgibbs			adwexecuteacb(acb, NULL, 0, 0);
50740024Sgibbs		}
50840024Sgibbs		break;
50940024Sgibbs	}
51040024Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
51140024Sgibbs	{
51240024Sgibbs		adw_idle_cmd_status_t status;
51340024Sgibbs
51440024Sgibbs		adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
51540024Sgibbs				  ccb->ccb_h.target_id);
51640024Sgibbs		status = adw_idle_cmd_wait(adw);
51740024Sgibbs		if (status == ADW_IDLE_CMD_SUCCESS) {
51840024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
51940024Sgibbs			if (bootverbose) {
52040024Sgibbs				xpt_print_path(ccb->ccb_h.path);
52140024Sgibbs				printf("BDR Delivered\n");
52240024Sgibbs			}
52340024Sgibbs		} else
52440024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
52540024Sgibbs		xpt_done(ccb);
52640024Sgibbs		break;
52740024Sgibbs	}
52840024Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
52940024Sgibbs		/* XXX Implement */
53040024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
53140024Sgibbs		xpt_done(ccb);
53240024Sgibbs		break;
53340024Sgibbs	case XPT_SET_TRAN_SETTINGS:
53440024Sgibbs	{
53540024Sgibbs		struct	  ccb_trans_settings *cts;
53640024Sgibbs		u_int	  target_mask;
53740024Sgibbs		int	  s;
53840024Sgibbs
53940024Sgibbs		cts = &ccb->cts;
54040024Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
54140024Sgibbs
54240024Sgibbs		s = splcam();
54340024Sgibbs		if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
54440024Sgibbs			if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
54540024Sgibbs				u_int discenb;
54640024Sgibbs
54740024Sgibbs				discenb =
54840024Sgibbs				    adw_lram_read_16(adw, ADW_MC_DISC_ENABLE);
54940024Sgibbs
55040024Sgibbs				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
55140024Sgibbs					discenb |= target_mask;
55240024Sgibbs				else
55340024Sgibbs					discenb &= ~target_mask;
55440024Sgibbs
55540024Sgibbs				adw_lram_write_16(adw, ADW_MC_DISC_ENABLE,
55640024Sgibbs						  discenb);
55740024Sgibbs			}
55840024Sgibbs
55940024Sgibbs			if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
56040024Sgibbs
56140024Sgibbs				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
56240024Sgibbs					adw->tagenb |= target_mask;
56340024Sgibbs				else
56440024Sgibbs					adw->tagenb &= ~target_mask;
56540024Sgibbs			}
56640024Sgibbs
56740024Sgibbs			if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
56840024Sgibbs				u_int wdtrenb_orig;
56940024Sgibbs				u_int wdtrenb;
57040024Sgibbs				u_int wdtrdone;
57140024Sgibbs
57240024Sgibbs				wdtrenb_orig =
57340024Sgibbs				    adw_lram_read_16(adw, ADW_MC_WDTR_ABLE);
57440024Sgibbs				wdtrenb = wdtrenb_orig;
57540024Sgibbs				wdtrdone = adw_lram_read_16(adw,
57640024Sgibbs							    ADW_MC_WDTR_DONE);
57740024Sgibbs				switch (cts->bus_width) {
57840024Sgibbs				case MSG_EXT_WDTR_BUS_32_BIT:
57940024Sgibbs				case MSG_EXT_WDTR_BUS_16_BIT:
58040024Sgibbs					wdtrenb |= target_mask;
58140024Sgibbs					break;
58240024Sgibbs				case MSG_EXT_WDTR_BUS_8_BIT:
58340024Sgibbs				default:
58440024Sgibbs					wdtrenb &= ~target_mask;
58540024Sgibbs					break;
58640024Sgibbs				}
58740024Sgibbs				if (wdtrenb != wdtrenb_orig) {
58840024Sgibbs					adw_lram_write_16(adw,
58940024Sgibbs							  ADW_MC_WDTR_ABLE,
59040024Sgibbs							  wdtrenb);
59140024Sgibbs					wdtrdone &= ~target_mask;
59240024Sgibbs					adw_lram_write_16(adw,
59340024Sgibbs							  ADW_MC_WDTR_DONE,
59440024Sgibbs							  wdtrdone);
59540024Sgibbs				}
59640024Sgibbs			}
59740024Sgibbs
59846581Sken			if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
59946581Sken			 || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
60040024Sgibbs				u_int sdtrenb_orig;
60140024Sgibbs				u_int sdtrenb;
60240024Sgibbs				u_int ultraenb_orig;
60340024Sgibbs				u_int ultraenb;
60440024Sgibbs				u_int sdtrdone;
60540024Sgibbs
60640024Sgibbs				sdtrenb_orig =
60740024Sgibbs				    adw_lram_read_16(adw, ADW_MC_SDTR_ABLE);
60840024Sgibbs				sdtrenb = sdtrenb_orig;
60940024Sgibbs
61040024Sgibbs				ultraenb_orig =
61140024Sgibbs				    adw_lram_read_16(adw, ADW_MC_ULTRA_ABLE);
61240024Sgibbs				ultraenb = ultraenb_orig;
61340024Sgibbs
61440024Sgibbs				sdtrdone = adw_lram_read_16(adw,
61540024Sgibbs							    ADW_MC_SDTR_DONE);
61640024Sgibbs
61746581Sken				if ((cts->valid
61846581Sken				   & CCB_TRANS_SYNC_RATE_VALID) != 0) {
61946581Sken
62046581Sken					if (cts->sync_period == 0) {
62146581Sken						sdtrenb &= ~target_mask;
62246581Sken					} else if (cts->sync_period > 12) {
62346581Sken						ultraenb &= ~target_mask;
62446581Sken						sdtrenb |= target_mask;
62546581Sken					} else {
62646581Sken						ultraenb |= target_mask;
62746581Sken						sdtrenb |= target_mask;
62846581Sken					}
62940024Sgibbs				}
63040024Sgibbs
63140024Sgibbs				if ((cts->valid
63240024Sgibbs				   & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
63340024Sgibbs					if (cts->sync_offset == 0)
63440024Sgibbs						sdtrenb &= ~target_mask;
63540024Sgibbs				}
63640024Sgibbs
63740024Sgibbs				if (sdtrenb != sdtrenb_orig
63840024Sgibbs				 || ultraenb != ultraenb_orig) {
63940024Sgibbs					adw_lram_write_16(adw, ADW_MC_SDTR_ABLE,
64040024Sgibbs							  sdtrenb);
64140024Sgibbs					adw_lram_write_16(adw,
64240024Sgibbs							  ADW_MC_ULTRA_ABLE,
64340024Sgibbs							  ultraenb);
64440024Sgibbs					sdtrdone &= ~target_mask;
64540024Sgibbs					adw_lram_write_16(adw, ADW_MC_SDTR_DONE,
64640024Sgibbs							  sdtrdone);
64740024Sgibbs				}
64840024Sgibbs			}
64940024Sgibbs		}
65040024Sgibbs		splx(s);
65140024Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
65240024Sgibbs		xpt_done(ccb);
65340024Sgibbs		break;
65440024Sgibbs	}
65540024Sgibbs	case XPT_GET_TRAN_SETTINGS:
65640024Sgibbs	/* Get default/user set transfer settings for the target */
65740024Sgibbs	{
65840024Sgibbs		struct	ccb_trans_settings *cts;
65940024Sgibbs		u_int	target_mask;
66040024Sgibbs
66140024Sgibbs		cts = &ccb->cts;
66240024Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
66340024Sgibbs		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
66440024Sgibbs			cts->flags = 0;
66540024Sgibbs			if ((adw->user_discenb & target_mask) != 0)
66640024Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
66740024Sgibbs
66840024Sgibbs			if ((adw->user_tagenb & target_mask) != 0)
66940024Sgibbs				cts->flags |= CCB_TRANS_TAG_ENB;
67040024Sgibbs
67140024Sgibbs			if ((adw->user_wdtr & target_mask) != 0)
67240024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
67340024Sgibbs			else
67440024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
67540024Sgibbs
67640024Sgibbs			if ((adw->user_sdtr & target_mask) != 0) {
67740024Sgibbs				if ((adw->user_ultra & target_mask) != 0)
67840024Sgibbs					cts->sync_period = 12; /* 20MHz */
67940024Sgibbs				else
68040024Sgibbs					cts->sync_period = 25; /* 10MHz */
68140024Sgibbs				cts->sync_offset = 15; /* XXX ??? */
68240024Sgibbs			}
68340024Sgibbs
68440024Sgibbs			cts->valid = CCB_TRANS_SYNC_RATE_VALID
68540024Sgibbs				   | CCB_TRANS_SYNC_OFFSET_VALID
68640024Sgibbs				   | CCB_TRANS_BUS_WIDTH_VALID
68740024Sgibbs				   | CCB_TRANS_DISC_VALID
68840024Sgibbs				   | CCB_TRANS_TQ_VALID;
68940024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
69040024Sgibbs		} else {
69140024Sgibbs			u_int targ_tinfo;
69240024Sgibbs
69340024Sgibbs			cts->flags = 0;
69440024Sgibbs			if ((adw_lram_read_16(adw, ADW_MC_DISC_ENABLE)
69540024Sgibbs			  & target_mask) != 0)
69640024Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
69740024Sgibbs
69840024Sgibbs			if ((adw->tagenb & target_mask) != 0)
69940024Sgibbs				cts->flags |= CCB_TRANS_TAG_ENB;
70040024Sgibbs
70140024Sgibbs			targ_tinfo =
70240024Sgibbs			    adw_lram_read_16(adw,
70340024Sgibbs					     ADW_MC_DEVICE_HSHK_CFG_TABLE
70440024Sgibbs					     + (2 * ccb->ccb_h.target_id));
70540024Sgibbs
70640024Sgibbs			if ((targ_tinfo & ADW_HSHK_CFG_WIDE_XFR) != 0)
70740024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
70840024Sgibbs			else
70940024Sgibbs				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
71040024Sgibbs
71140024Sgibbs			cts->sync_period =
71240024Sgibbs			    ADW_HSHK_CFG_PERIOD_FACTOR(targ_tinfo);
71340024Sgibbs
71440024Sgibbs			cts->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET;
71540024Sgibbs			if (cts->sync_period == 0)
71640024Sgibbs				cts->sync_offset = 0;
71740024Sgibbs
71840024Sgibbs			if (cts->sync_offset == 0)
71940024Sgibbs				cts->sync_period = 0;
72040024Sgibbs		}
72140024Sgibbs		cts->valid = CCB_TRANS_SYNC_RATE_VALID
72240024Sgibbs			   | CCB_TRANS_SYNC_OFFSET_VALID
72340024Sgibbs			   | CCB_TRANS_BUS_WIDTH_VALID
72440024Sgibbs			   | CCB_TRANS_DISC_VALID
72540024Sgibbs			   | CCB_TRANS_TQ_VALID;
72640024Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
72740024Sgibbs		xpt_done(ccb);
72840024Sgibbs		break;
72940024Sgibbs	}
73040024Sgibbs	case XPT_CALC_GEOMETRY:
73140024Sgibbs	{
73240024Sgibbs		struct	  ccb_calc_geometry *ccg;
73340024Sgibbs		u_int32_t size_mb;
73440024Sgibbs		u_int32_t secs_per_cylinder;
73540024Sgibbs		int	  extended;
73640024Sgibbs
73740024Sgibbs		/*
73840024Sgibbs		 * XXX Use Adaptec translation until I find out how to
73940024Sgibbs		 *     get this information from the card.
74040024Sgibbs		 */
74140024Sgibbs		ccg = &ccb->ccg;
74240024Sgibbs		size_mb = ccg->volume_size
74340024Sgibbs			/ ((1024L * 1024L) / ccg->block_size);
74440024Sgibbs		extended = 1;
74540024Sgibbs
74640024Sgibbs		if (size_mb > 1024 && extended) {
74740024Sgibbs			ccg->heads = 255;
74840024Sgibbs			ccg->secs_per_track = 63;
74940024Sgibbs		} else {
75040024Sgibbs			ccg->heads = 64;
75140024Sgibbs			ccg->secs_per_track = 32;
75240024Sgibbs		}
75340024Sgibbs		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
75440024Sgibbs		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
75540024Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
75640024Sgibbs		xpt_done(ccb);
75740024Sgibbs		break;
75840024Sgibbs	}
75940024Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
76040024Sgibbs	{
76140024Sgibbs		adw_idle_cmd_status_t status;
76240024Sgibbs
76340024Sgibbs		adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET, /*param*/0);
76440024Sgibbs		status = adw_idle_cmd_wait(adw);
76540024Sgibbs		if (status == ADW_IDLE_CMD_SUCCESS) {
76640024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
76740024Sgibbs			if (bootverbose) {
76840024Sgibbs				xpt_print_path(adw->path);
76940024Sgibbs				printf("Bus Reset Delivered\n");
77040024Sgibbs			}
77140024Sgibbs		} else
77240024Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
77340024Sgibbs		xpt_done(ccb);
77440024Sgibbs		break;
77540024Sgibbs	}
77640024Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
77740024Sgibbs		/* XXX Implement */
77840024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
77940024Sgibbs		xpt_done(ccb);
78040024Sgibbs		break;
78140024Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
78240024Sgibbs	{
78340024Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
78440024Sgibbs
78540024Sgibbs		cpi->version_num = 1;
78640024Sgibbs		cpi->hba_inquiry = PI_WIDE_16|PI_SDTR_ABLE|PI_TAG_ABLE;
78740024Sgibbs		cpi->target_sprt = 0;
78840024Sgibbs		cpi->hba_misc = 0;
78940024Sgibbs		cpi->hba_eng_cnt = 0;
79040024Sgibbs		cpi->max_target = ADW_MAX_TID;
79140024Sgibbs		cpi->max_lun = ADW_MAX_LUN;
79240024Sgibbs		cpi->initiator_id = adw->initiator_id;
79340024Sgibbs		cpi->bus_id = cam_sim_bus(sim);
79446581Sken		cpi->base_transfer_speed = 3300;
79540024Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
79640024Sgibbs		strncpy(cpi->hba_vid, "AdvanSys", HBA_IDLEN);
79740024Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
79840024Sgibbs		cpi->unit_number = cam_sim_unit(sim);
79940024Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
80040024Sgibbs		xpt_done(ccb);
80140024Sgibbs		break;
80240024Sgibbs	}
80340024Sgibbs	default:
80440024Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
80540024Sgibbs		xpt_done(ccb);
80640024Sgibbs		break;
80740024Sgibbs	}
80840024Sgibbs}
80940024Sgibbs
81040024Sgibbsstatic void
81140024Sgibbsadw_poll(struct cam_sim *sim)
81240024Sgibbs{
81340024Sgibbs	adw_intr(cam_sim_softc(sim));
81440024Sgibbs}
81540024Sgibbs
81640024Sgibbsstatic void
81740024Sgibbsadw_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
81840024Sgibbs{
81940024Sgibbs}
82040024Sgibbs
82140024Sgibbsstruct adw_softc *
82240024Sgibbsadw_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh)
82340024Sgibbs{
82440024Sgibbs	struct	 adw_softc *adw;
82540024Sgibbs	int	 i;
82640024Sgibbs
82740024Sgibbs	/*
82840024Sgibbs	 * Allocate a storage area for us
82940024Sgibbs	 */
83040024Sgibbs	adw = malloc(sizeof(struct adw_softc), M_DEVBUF, M_NOWAIT);
83140024Sgibbs	if (adw == NULL) {
83240024Sgibbs		printf("adw%d: cannot malloc!\n", unit);
83340024Sgibbs		return NULL;
83440024Sgibbs	}
83540024Sgibbs	bzero(adw, sizeof(struct adw_softc));
83640024Sgibbs	LIST_INIT(&adw->pending_ccbs);
83740024Sgibbs	SLIST_INIT(&adw->sg_maps);
83840024Sgibbs	adw->unit = unit;
83940024Sgibbs	adw->tag = tag;
84040024Sgibbs	adw->bsh = bsh;
84140024Sgibbs	i = adw->unit / 10;
84240024Sgibbs	adw->name = malloc(sizeof("adw") + i + 1, M_DEVBUF, M_NOWAIT);
84340024Sgibbs	if (adw->name == NULL) {
84440024Sgibbs		printf("adw%d: cannot malloc name!\n", unit);
84540024Sgibbs		free(adw, M_DEVBUF);
84640024Sgibbs		return NULL;
84740024Sgibbs	}
84840024Sgibbs	sprintf(adw->name, "adw%d", adw->unit);
84940024Sgibbs	return(adw);
85040024Sgibbs}
85140024Sgibbs
85240024Sgibbsvoid
85340024Sgibbsadw_free(struct adw_softc *adw)
85440024Sgibbs{
85540024Sgibbs	switch (adw->init_level) {
85640024Sgibbs	case 6:
85740024Sgibbs	{
85840024Sgibbs		struct sg_map_node *sg_map;
85940024Sgibbs
86040024Sgibbs		while ((sg_map = SLIST_FIRST(&adw->sg_maps)) != NULL) {
86140024Sgibbs			SLIST_REMOVE_HEAD(&adw->sg_maps, links);
86240024Sgibbs			bus_dmamap_unload(adw->sg_dmat,
86340024Sgibbs					  sg_map->sg_dmamap);
86440024Sgibbs			bus_dmamem_free(adw->sg_dmat, sg_map->sg_vaddr,
86540024Sgibbs					sg_map->sg_dmamap);
86640024Sgibbs			free(sg_map, M_DEVBUF);
86740024Sgibbs		}
86840024Sgibbs		bus_dma_tag_destroy(adw->sg_dmat);
86940024Sgibbs	}
87040024Sgibbs	case 5:
87140024Sgibbs		bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap);
87240024Sgibbs	case 4:
87340024Sgibbs		bus_dmamem_free(adw->acb_dmat, adw->acbs,
87440024Sgibbs				adw->acb_dmamap);
87540024Sgibbs		bus_dmamap_destroy(adw->acb_dmat, adw->acb_dmamap);
87640024Sgibbs	case 3:
87740024Sgibbs		bus_dma_tag_destroy(adw->acb_dmat);
87840024Sgibbs	case 2:
87940024Sgibbs		bus_dma_tag_destroy(adw->buffer_dmat);
88040024Sgibbs	case 1:
88140024Sgibbs		bus_dma_tag_destroy(adw->parent_dmat);
88240024Sgibbs	case 0:
88340024Sgibbs		break;
88440024Sgibbs	}
88540024Sgibbs	free(adw->name, M_DEVBUF);
88640024Sgibbs	free(adw, M_DEVBUF);
88740024Sgibbs}
88840024Sgibbs
88940024Sgibbsint
89040024Sgibbsadw_init(struct adw_softc *adw)
89140024Sgibbs{
89240024Sgibbs	struct	  adw_eeprom eep_config;
89340024Sgibbs	u_int16_t checksum;
89440024Sgibbs	u_int16_t scsicfg1;
89540024Sgibbs
89640024Sgibbs	adw_reset_chip(adw);
89740024Sgibbs	checksum = adw_eeprom_read(adw, &eep_config);
89840024Sgibbs	bcopy(eep_config.serial_number, adw->serial_number,
89940024Sgibbs	      sizeof(adw->serial_number));
90040024Sgibbs	if (checksum != eep_config.checksum) {
90140024Sgibbs		u_int16_t serial_number[3];
90240024Sgibbs
90340024Sgibbs		printf("%s: EEPROM checksum failed.  Restoring Defaults\n",
90440024Sgibbs		       adw_name(adw));
90540024Sgibbs
90640024Sgibbs	        /*
90740024Sgibbs		 * Restore the default EEPROM settings.
90840024Sgibbs		 * Assume the 6 byte board serial number that was read
90940024Sgibbs		 * from EEPROM is correct even if the EEPROM checksum
91040024Sgibbs		 * failed.
91140024Sgibbs		 */
91240024Sgibbs		bcopy(&adw_default_eeprom, &eep_config, sizeof(eep_config));
91340024Sgibbs		bcopy(adw->serial_number, eep_config.serial_number,
91440024Sgibbs		      sizeof(serial_number));
91540024Sgibbs		adw_eeprom_write(adw, &eep_config);
91640024Sgibbs	}
91740024Sgibbs
91840024Sgibbs	/* Pull eeprom information into our softc. */
91940024Sgibbs	adw->bios_ctrl = eep_config.bios_ctrl;
92040024Sgibbs	adw->user_wdtr = eep_config.wdtr_able;
92140024Sgibbs	adw->user_sdtr = eep_config.sdtr_able;
92240024Sgibbs	adw->user_ultra = eep_config.ultra_able;
92340024Sgibbs	adw->user_tagenb = eep_config.tagqng_able;
92440024Sgibbs	adw->user_discenb = eep_config.disc_enable;
92540024Sgibbs	adw->max_acbs = eep_config.max_host_qng;
92640024Sgibbs	adw->initiator_id = (eep_config.adapter_scsi_id & ADW_MAX_TID);
92740024Sgibbs
92840024Sgibbs	/*
92940024Sgibbs	 * Sanity check the number of host openings.
93040024Sgibbs	 */
93140024Sgibbs	if (adw->max_acbs > ADW_DEF_MAX_HOST_QNG)
93240024Sgibbs		adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
93340024Sgibbs	else if (adw->max_acbs < ADW_DEF_MIN_HOST_QNG) {
93440024Sgibbs        	/* If the value is zero, assume it is uninitialized. */
93540024Sgibbs		if (adw->max_acbs == 0)
93640024Sgibbs			adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
93740024Sgibbs		else
93840024Sgibbs			adw->max_acbs = ADW_DEF_MIN_HOST_QNG;
93940024Sgibbs
94040024Sgibbs	}
94140024Sgibbs
94240024Sgibbs	scsicfg1 = 0;
94340024Sgibbs	switch (eep_config.termination) {
94440024Sgibbs	default:
94540024Sgibbs		printf("%s: Invalid EEPROM Termination Settings.\n",
94640024Sgibbs		       adw_name(adw));
94740024Sgibbs		printf("%s: Reverting to Automatic Termination\n",
94840024Sgibbs		       adw_name(adw));
94940024Sgibbs		/* FALLTHROUGH */
95040024Sgibbs	case ADW_EEPROM_TERM_AUTO:
95140024Sgibbs		break;
95240024Sgibbs	case ADW_EEPROM_TERM_BOTH_ON:
95340024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L;
95440024Sgibbs		/* FALLTHROUGH */
95540024Sgibbs	case ADW_EEPROM_TERM_HIGH_ON:
95640024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H;
95740024Sgibbs		/* FALLTHROUGH */
95840024Sgibbs	case ADW_EEPROM_TERM_OFF:
95940024Sgibbs		scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL;
96040024Sgibbs		break;
96140024Sgibbs	}
96240024Sgibbs
96340024Sgibbs	printf("%s: SCSI ID %d, ", adw_name(adw), adw->initiator_id);
96440024Sgibbs
96540024Sgibbs	if (adw_init_chip(adw, scsicfg1) != 0)
96640024Sgibbs		return (-1);
96740024Sgibbs
96840024Sgibbs	printf("Queue Depth %d\n", adw->max_acbs);
96940024Sgibbs
97040024Sgibbs	/* DMA tag for mapping buffers into device visible space. */
97140024Sgibbs	if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/0, /*boundary*/0,
97240024Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
97340024Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
97440024Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
97540024Sgibbs			       /*maxsize*/MAXBSIZE, /*nsegments*/ADW_SGSIZE,
97640024Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
97740024Sgibbs			       /*flags*/BUS_DMA_ALLOCNOW,
97840024Sgibbs			       &adw->buffer_dmat) != 0) {
97940024Sgibbs		return (-1);
98040024Sgibbs	}
98140024Sgibbs
98240024Sgibbs	adw->init_level++;
98340024Sgibbs
98440024Sgibbs	/* DMA tag for our ccb structures */
98540024Sgibbs	if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/0, /*boundary*/0,
98640024Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
98740024Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
98840024Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
98940024Sgibbs			       adw->max_acbs * sizeof(struct acb),
99040024Sgibbs			       /*nsegments*/1,
99140024Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
99240024Sgibbs			       /*flags*/0, &adw->acb_dmat) != 0) {
99340024Sgibbs		return (-1);
99440024Sgibbs        }
99540024Sgibbs
99640024Sgibbs	adw->init_level++;
99740024Sgibbs
99840024Sgibbs	/* Allocation for our ccbs */
99940024Sgibbs	if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs,
100040024Sgibbs			     BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0) {
100140024Sgibbs		return (-1);
100240024Sgibbs	}
100340024Sgibbs
100440024Sgibbs	adw->init_level++;
100540024Sgibbs
100640024Sgibbs	/* And permanently map them */
100740024Sgibbs	bus_dmamap_load(adw->acb_dmat, adw->acb_dmamap,
100840024Sgibbs			adw->acbs,
100940024Sgibbs			adw->max_acbs * sizeof(struct acb),
101040024Sgibbs			adwmapmem, &adw->acb_busbase, /*flags*/0);
101140024Sgibbs
101240024Sgibbs	/* Clear them out. */
101340024Sgibbs	bzero(adw->acbs, adw->max_acbs * sizeof(struct acb));
101440024Sgibbs
101540024Sgibbs	/* DMA tag for our S/G structures.  We allocate in page sized chunks */
101640024Sgibbs	if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/0, /*boundary*/0,
101740024Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
101840024Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
101940024Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
102040024Sgibbs			       PAGE_SIZE, /*nsegments*/1,
102140024Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
102240024Sgibbs			       /*flags*/0, &adw->sg_dmat) != 0) {
102340024Sgibbs		return (-1);
102440024Sgibbs        }
102540024Sgibbs
102640024Sgibbs	adw->init_level++;
102740024Sgibbs
102840024Sgibbs	/* Allocate our first batch of ccbs */
102940024Sgibbs	if (adwallocacbs(adw) == 0)
103040024Sgibbs		return (-1);
103140024Sgibbs
103240024Sgibbs	return (0);
103340024Sgibbs}
103440024Sgibbs
103540024Sgibbs/*
103640024Sgibbs * Attach all the sub-devices we can find
103740024Sgibbs */
103840024Sgibbsint
103940024Sgibbsadw_attach(struct adw_softc *adw)
104040024Sgibbs{
104140024Sgibbs	struct ccb_setasync csa;
104240024Sgibbs	struct cam_devq *devq;
104340024Sgibbs
104440024Sgibbs	/* Start the Risc processor now that we are fully configured. */
104540024Sgibbs	adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN);
104640024Sgibbs
104740024Sgibbs	/*
104840024Sgibbs	 * Create the device queue for our SIM.
104940024Sgibbs	 */
105040024Sgibbs	devq = cam_simq_alloc(adw->max_acbs);
105140024Sgibbs	if (devq == NULL)
105240024Sgibbs		return (0);
105340024Sgibbs
105440024Sgibbs	/*
105540024Sgibbs	 * Construct our SIM entry.
105640024Sgibbs	 */
105740024Sgibbs	adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw, adw->unit,
105840024Sgibbs				 1, adw->max_acbs, devq);
105940024Sgibbs	if (adw->sim == NULL)
106040024Sgibbs		return (0);
106140024Sgibbs
106240024Sgibbs	/*
106340024Sgibbs	 * Register the bus.
106440024Sgibbs	 */
106540024Sgibbs	if (xpt_bus_register(adw->sim, 0) != CAM_SUCCESS) {
106640024Sgibbs		cam_sim_free(adw->sim, /*free devq*/TRUE);
106740024Sgibbs		return (0);
106840024Sgibbs	}
106940024Sgibbs
107040024Sgibbs	if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim),
107140024Sgibbs			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
107240024Sgibbs	   == CAM_REQ_CMP) {
107340024Sgibbs		xpt_setup_ccb(&csa.ccb_h, adw->path, /*priority*/5);
107440024Sgibbs		csa.ccb_h.func_code = XPT_SASYNC_CB;
107540024Sgibbs		csa.event_enable = AC_LOST_DEVICE;
107640024Sgibbs		csa.callback = adw_async;
107740024Sgibbs		csa.callback_arg = adw;
107840024Sgibbs		xpt_action((union ccb *)&csa);
107940024Sgibbs	}
108040024Sgibbs
108140024Sgibbs	return (0);
108240024Sgibbs}
108340024Sgibbs
108440024Sgibbsvoid
108540024Sgibbsadw_intr(void *arg)
108640024Sgibbs{
108740024Sgibbs	struct	adw_softc *adw;
108840024Sgibbs	u_int	int_stat;
108940024Sgibbs	u_int	next_doneq;
109040024Sgibbs	u_int	next_completeq;
109140024Sgibbs	u_int	doneq_start;
109240024Sgibbs
109340024Sgibbs	adw = (struct adw_softc *)arg;
109440024Sgibbs	if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0)
109540024Sgibbs		return;
109640024Sgibbs
109740024Sgibbs	/* Reading the register clears the interrupt. */
109840024Sgibbs	int_stat = adw_inb(adw, ADW_INTR_STATUS_REG);
109940024Sgibbs
110040024Sgibbs	if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) {
110140024Sgibbs		/* Idle Command Complete */
110240024Sgibbs		adw->idle_command_cmp = 1;
110340024Sgibbs		switch (adw->idle_cmd) {
110440024Sgibbs		case ADW_IDLE_CMD_DEVICE_RESET:
110540024Sgibbs			adw_handle_device_reset(adw,
110640024Sgibbs						/*target*/adw->idle_cmd_param);
110740024Sgibbs			break;
110840024Sgibbs		case ADW_IDLE_CMD_SCSI_RESET:
110940024Sgibbs			adw_handle_bus_reset(adw, /*initiated*/TRUE);
111040024Sgibbs			break;
111140024Sgibbs		default:
111240024Sgibbs			break;
111340024Sgibbs		}
111440024Sgibbs		adw->idle_cmd = ADW_IDLE_CMD_COMPLETED;
111540024Sgibbs	}
111640024Sgibbs
111740024Sgibbs	if ((int_stat & ADW_INTR_STATUS_INTRC) != 0) {
111840024Sgibbs		/* SCSI Bus Reset */
111940024Sgibbs		adw_handle_bus_reset(adw, /*initiated*/FALSE);
112040024Sgibbs        }
112140024Sgibbs
112240024Sgibbs	/*
112340024Sgibbs	 * ADW_MC_HOST_NEXT_DONE is actually the last completed RISC
112440024Sgibbs	 * Queue List request. Its forward pointer (RQL_FWD) points to the
112540024Sgibbs	 * current completed RISC Queue List request.
112640024Sgibbs	 */
112740024Sgibbs	next_doneq = adw_lram_read_8(adw, ADW_MC_HOST_NEXT_DONE);
112840024Sgibbs	next_doneq = ADW_MC_RISC_Q_LIST_BASE + RQL_FWD
112940024Sgibbs		   + (next_doneq * ADW_MC_RISC_Q_LIST_SIZE);
113040024Sgibbs
113140024Sgibbs	next_completeq = adw_lram_read_8(adw, next_doneq);
113240024Sgibbs	doneq_start = ADW_MC_NULL_Q;
113340024Sgibbs	/* Loop until all completed Q's are processed. */
113440024Sgibbs	while (next_completeq != ADW_MC_NULL_Q) {
113540024Sgibbs		u_int32_t acb_busaddr;
113640024Sgibbs		struct	  acb *acb;
113740024Sgibbs		union	  ccb *ccb;
113840024Sgibbs
113940024Sgibbs		doneq_start = next_completeq;
114040024Sgibbs
114140024Sgibbs		next_doneq = ADW_MC_RISC_Q_LIST_BASE +
114240024Sgibbs			     (next_completeq * ADW_MC_RISC_Q_LIST_SIZE);
114340024Sgibbs
114440024Sgibbs		/*
114540024Sgibbs		 * Read the ADW_SCSI_REQ_Q physical address pointer from
114640024Sgibbs		 * the RISC list entry.
114740024Sgibbs		 */
114840024Sgibbs		acb_busaddr = adw_lram_read_32(adw, next_doneq + RQL_PHYADDR);
114940024Sgibbs		acb = acbptov(adw, acb_busaddr);
115040024Sgibbs
115140024Sgibbs		/* Change the RISC Queue List state to free. */
115240024Sgibbs		adw_lram_write_8(adw, next_doneq + RQL_STATE, ADW_MC_QS_FREE);
115340024Sgibbs
115440024Sgibbs		/* Get the RISC Queue List forward pointer. */
115540024Sgibbs		next_completeq = adw_lram_read_8(adw, next_doneq + RQL_FWD);
115640024Sgibbs
115740024Sgibbs		/* Process CCB */
115840024Sgibbs		ccb = acb->ccb;
115940024Sgibbs		untimeout(adwtimeout, acb, ccb->ccb_h.timeout_ch);
116040024Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
116140024Sgibbs			bus_dmasync_op_t op;
116240024Sgibbs
116340024Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
116440024Sgibbs				op = BUS_DMASYNC_POSTREAD;
116540024Sgibbs			else
116640024Sgibbs				op = BUS_DMASYNC_POSTWRITE;
116740024Sgibbs			bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
116840024Sgibbs			bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
116940024Sgibbs			ccb->csio.resid = acb->queue.data_cnt;
117040024Sgibbs		} else
117140024Sgibbs			ccb->csio.resid = 0;
117240024Sgibbs
117340024Sgibbs		/* Common Cases inline... */
117440024Sgibbs		if (acb->queue.host_status == QHSTA_NO_ERROR
117540024Sgibbs		 && (acb->queue.done_status == QD_NO_ERROR
117640024Sgibbs		  || acb->queue.done_status == QD_WITH_ERROR)) {
117740024Sgibbs			ccb->csio.scsi_status = acb->queue.scsi_status;
117840024Sgibbs			ccb->ccb_h.status = 0;
117940024Sgibbs			switch (ccb->csio.scsi_status) {
118040024Sgibbs			case SCSI_STATUS_OK:
118140024Sgibbs				ccb->ccb_h.status |= CAM_REQ_CMP;
118240024Sgibbs				break;
118340024Sgibbs			case SCSI_STATUS_CHECK_COND:
118440024Sgibbs			case SCSI_STATUS_CMD_TERMINATED:
118540024Sgibbs				bcopy(&acb->sense_data, &ccb->csio.sense_data,
118640024Sgibbs				      ccb->csio.sense_len);
118740024Sgibbs				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
118840024Sgibbs				ccb->csio.sense_resid = acb->queue.sense_len;
118940024Sgibbs				/* FALLTHROUGH */
119040024Sgibbs			default:
119140024Sgibbs				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR
119240024Sgibbs						  |  CAM_DEV_QFRZN;
119340024Sgibbs				xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
119440024Sgibbs				break;
119540024Sgibbs			}
119640024Sgibbs			adwfreeacb(adw, acb);
119740024Sgibbs			xpt_done(ccb);
119840024Sgibbs
119940024Sgibbs		} else {
120040024Sgibbs			adwprocesserror(adw, acb);
120140024Sgibbs		}
120240024Sgibbs	}
120340024Sgibbs
120440024Sgibbs	if (doneq_start != ADW_MC_NULL_Q)
120540024Sgibbs		adw_lram_write_8(adw, ADW_MC_HOST_NEXT_DONE, doneq_start);
120640024Sgibbs}
120740024Sgibbs
120840024Sgibbsstatic void
120940024Sgibbsadwprocesserror(struct adw_softc *adw, struct acb *acb)
121040024Sgibbs{
121140024Sgibbs	union ccb *ccb;
121240024Sgibbs
121340024Sgibbs	ccb = acb->ccb;
121440024Sgibbs	if (acb->queue.done_status == QD_ABORTED_BY_HOST) {
121540024Sgibbs		ccb->ccb_h.status = CAM_REQ_ABORTED;
121640024Sgibbs	} else {
121740024Sgibbs
121840024Sgibbs		switch (acb->queue.host_status) {
121940024Sgibbs		case QHSTA_M_SEL_TIMEOUT:
122040024Sgibbs			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
122140024Sgibbs			break;
122240024Sgibbs		case QHSTA_M_SXFR_OFF_UFLW:
122340024Sgibbs		case QHSTA_M_SXFR_OFF_OFLW:
122440024Sgibbs		case QHSTA_M_DATA_OVER_RUN:
122540024Sgibbs			ccb->ccb_h.status = CAM_DATA_RUN_ERR;
122640024Sgibbs			break;
122740024Sgibbs		case QHSTA_M_SXFR_DESELECTED:
122840024Sgibbs		case QHSTA_M_UNEXPECTED_BUS_FREE:
122940024Sgibbs			ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
123040024Sgibbs			break;
123140024Sgibbs		case QHSTA_M_QUEUE_ABORTED:
123240024Sgibbs			/* BDR or Bus Reset */
123340024Sgibbs			ccb->ccb_h.status = adw->last_reset;
123440024Sgibbs			break;
123540024Sgibbs		case QHSTA_M_SXFR_SDMA_ERR:
123640024Sgibbs		case QHSTA_M_SXFR_SXFR_PERR:
123740024Sgibbs		case QHSTA_M_RDMA_PERR:
123840024Sgibbs			ccb->ccb_h.status = CAM_UNCOR_PARITY;
123940024Sgibbs			break;
124040024Sgibbs		case QHSTA_M_WTM_TIMEOUT:
124140024Sgibbs		case QHSTA_M_SXFR_WD_TMO:
124240024Sgibbs			/* The SCSI bus hung in a phase */
124340024Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
124440024Sgibbs			adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET,
124540024Sgibbs					  /*param*/0);
124640024Sgibbs			break;
124740024Sgibbs		case QHSTA_M_SXFR_XFR_PH_ERR:
124840024Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
124940024Sgibbs			break;
125040024Sgibbs		case QHSTA_M_SXFR_UNKNOWN_ERROR:
125140024Sgibbs			break;
125240024Sgibbs		case QHSTA_M_BAD_CMPL_STATUS_IN:
125340024Sgibbs			/* No command complete after a status message */
125440024Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
125540024Sgibbs			break;
125640024Sgibbs		case QHSTA_M_AUTO_REQ_SENSE_FAIL:
125740024Sgibbs			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
125840024Sgibbs			break;
125940024Sgibbs		case QHSTA_M_INVALID_DEVICE:
126040024Sgibbs			ccb->ccb_h.status = CAM_PATH_INVALID;
126140024Sgibbs			break;
126240024Sgibbs		case QHSTA_M_NO_AUTO_REQ_SENSE:
126340024Sgibbs			/*
126440024Sgibbs			 * User didn't request sense, but we got a
126540024Sgibbs			 * check condition.
126640024Sgibbs			 */
126740024Sgibbs			ccb->csio.scsi_status = acb->queue.scsi_status;
126840024Sgibbs			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
126940024Sgibbs			break;
127040024Sgibbs		default:
127140024Sgibbs			panic("%s: Unhandled Host status error %x",
127240024Sgibbs			      adw_name(adw), acb->queue.host_status);
127340024Sgibbs			/* NOTREACHED */
127440024Sgibbs		}
127540024Sgibbs	}
127640024Sgibbs	if (ccb->ccb_h.status != CAM_REQ_CMP) {
127740024Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
127840024Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
127940024Sgibbs	}
128040024Sgibbs	adwfreeacb(adw, acb);
128140024Sgibbs	xpt_done(ccb);
128240024Sgibbs}
128340024Sgibbs
128440024Sgibbsstatic void
128540024Sgibbsadwtimeout(void *arg)
128640024Sgibbs{
128740024Sgibbs	struct acb	     *acb;
128840024Sgibbs	union  ccb	     *ccb;
128940024Sgibbs	struct adw_softc     *adw;
129040024Sgibbs	adw_idle_cmd_status_t status;
129140024Sgibbs	int		      s;
129240024Sgibbs
129340024Sgibbs	acb = (struct acb *)arg;
129440024Sgibbs	ccb = acb->ccb;
129540024Sgibbs	adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
129640024Sgibbs	xpt_print_path(ccb->ccb_h.path);
129740024Sgibbs	printf("ACB %p - timed out\n", (void *)acb);
129840024Sgibbs
129940024Sgibbs	s = splcam();
130040024Sgibbs
130140024Sgibbs	if ((acb->state & ACB_ACTIVE) == 0) {
130240024Sgibbs		xpt_print_path(ccb->ccb_h.path);
130340024Sgibbs		printf("ACB %p - timed out CCB already completed\n",
130440024Sgibbs		       (void *)acb);
130540024Sgibbs		splx(s);
130640024Sgibbs		return;
130740024Sgibbs	}
130840024Sgibbs
130940024Sgibbs	/* Attempt a BDR first */
131040024Sgibbs	adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
131140024Sgibbs			  ccb->ccb_h.target_id);
131240024Sgibbs	splx(s);
131340024Sgibbs	status = adw_idle_cmd_wait(adw);
131440024Sgibbs	if (status == ADW_IDLE_CMD_SUCCESS) {
131540024Sgibbs		printf("%s: BDR Delivered.  No longer in timeout\n",
131640024Sgibbs		       adw_name(adw));
131740024Sgibbs	} else {
131840024Sgibbs		adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET, /*param*/0);
131940024Sgibbs		status = adw_idle_cmd_wait(adw);
132040024Sgibbs		if (status != ADW_IDLE_CMD_SUCCESS)
132140024Sgibbs			panic("%s: Bus Reset during timeout failed",
132240024Sgibbs			      adw_name(adw));
132340024Sgibbs	}
132440024Sgibbs}
132540024Sgibbs
132640024Sgibbsstatic void
132740024Sgibbsadw_handle_device_reset(struct adw_softc *adw, u_int target)
132840024Sgibbs{
132940024Sgibbs	struct cam_path *path;
133040024Sgibbs	cam_status error;
133140024Sgibbs
133240024Sgibbs	error = xpt_create_path(&path, /*periph*/NULL, cam_sim_path(adw->sim),
133340024Sgibbs				target, CAM_LUN_WILDCARD);
133440024Sgibbs
133540024Sgibbs	if (error == CAM_REQ_CMP) {
133640024Sgibbs		xpt_async(AC_SENT_BDR, path, NULL);
133740024Sgibbs		xpt_free_path(path);
133840024Sgibbs	}
133940024Sgibbs	adw->last_reset = CAM_BDR_SENT;
134040024Sgibbs}
134140024Sgibbs
134240024Sgibbsstatic void
134340024Sgibbsadw_handle_bus_reset(struct adw_softc *adw, int initiated)
134440024Sgibbs{
134540024Sgibbs	if (initiated) {
134640024Sgibbs		/*
134740024Sgibbs		 * The microcode currently sets the SCSI Bus Reset signal
134840024Sgibbs		 * while handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET
134940024Sgibbs		 * command above.  But the SCSI Bus Reset Hold Time in the
135040024Sgibbs		 * microcode is not deterministic (it may in fact be for less
135140024Sgibbs		 * than the SCSI Spec. minimum of 25 us).  Therefore on return
135240024Sgibbs		 * the Adv Library sets the SCSI Bus Reset signal for
135340024Sgibbs		 * ADW_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
135440024Sgibbs		 * than 25 us.
135540024Sgibbs		 */
135640024Sgibbs		u_int scsi_ctrl;
135740024Sgibbs
135840024Sgibbs	    	scsi_ctrl = adw_inw(adw, ADW_SCSI_CTRL) & ~ADW_SCSI_CTRL_RSTOUT;
135940024Sgibbs		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl | ADW_SCSI_CTRL_RSTOUT);
136040024Sgibbs		DELAY(ADW_SCSI_RESET_HOLD_TIME_US);
136140024Sgibbs		adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl);
136240024Sgibbs
136340024Sgibbs		/*
136440024Sgibbs		 * We will perform the async notification when the
136540024Sgibbs		 * SCSI Reset interrupt occurs.
136640024Sgibbs		 */
136740024Sgibbs	} else
136840024Sgibbs		xpt_async(AC_BUS_RESET, adw->path, NULL);
136940024Sgibbs	adw->last_reset = CAM_SCSI_BUS_RESET;
137040024Sgibbs}
1371