179697Snon/*	$NecBSD: scsi_low.c,v 1.24.10.8 2001/06/26 07:39:44 honda Exp $	*/
267468Snon/*	$NetBSD$	*/
367468Snon
4116162Sobrien#include <sys/cdefs.h>
5116162Sobrien__FBSDID("$FreeBSD$");
6116162Sobrien
767468Snon#define	SCSI_LOW_STATICS
879697Snon#define	SCSI_LOW_DEBUG
979697Snon#define SCSI_LOW_NEGOTIATE_BEFORE_SENSE
1079697Snon#define	SCSI_LOW_START_UP_CHECK
1179697Snon
1279697Snon/* #define	SCSI_LOW_INFO_DETAIL */
13116162Sobrien
1479697Snon/* #define	SCSI_LOW_QCLEAR_AFTER_CA */
1579697Snon/* #define	SCSI_LOW_FLAGS_QUIRKS_OK */
1679697Snon
1767468Snon#ifdef __NetBSD__
1867468Snon#define	SCSI_LOW_TARGET_OPEN
1979697Snon#endif	/* __NetBSD__ */
2067468Snon
2179697Snon#ifdef	__FreeBSD__
2279697Snon#define	SCSI_LOW_FLAGS_QUIRKS_OK
2379697Snon#endif	/* __FreeBSD__ */
2479697Snon
25139743Simp/*-
2667468Snon * [NetBSD for NEC PC-98 series]
2779697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
2867468Snon *	NetBSD/pc98 porting staff. All rights reserved.
2979697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
3067468Snon *	Naofumi HONDA. All rights reserved.
3179697Snon *
3279697Snon * [Ported for FreeBSD CAM]
3379697Snon *  Copyright (c) 2000, 2001
3479697Snon *      MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro.
3579697Snon *      All rights reserved.
3667468Snon *
3767468Snon *  Redistribution and use in source and binary forms, with or without
3867468Snon *  modification, are permitted provided that the following conditions
3967468Snon *  are met:
4067468Snon *  1. Redistributions of source code must retain the above copyright
4167468Snon *     notice, this list of conditions and the following disclaimer.
4267468Snon *  2. Redistributions in binary form must reproduce the above copyright
4367468Snon *     notice, this list of conditions and the following disclaimer in the
4467468Snon *     documentation and/or other materials provided with the distribution.
4567468Snon *  3. The name of the author may not be used to endorse or promote products
4667468Snon *     derived from this software without specific prior written permission.
4767468Snon *
4867468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4967468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
5067468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5167468Snon * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
5267468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5367468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
5467468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5567468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
5667468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
5767468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
5867468Snon * POSSIBILITY OF SUCH DAMAGE.
5967468Snon */
6067468Snon
6167468Snon/* <On the nexus establishment>
6267468Snon * When our host is reselected,
6367468Snon * nexus establish processes are little complicated.
6467468Snon * Normal steps are followings:
6579697Snon * 1) Our host selected by target => target nexus (slp->sl_Tnexus)
6679697Snon * 2) Identify msgin => lun nexus (slp->sl_Lnexus)
6779697Snon * 3) Qtag msg => ccb nexus (slp->sl_Qnexus)
6867468Snon */
6967468Snon#include "opt_ddb.h"
7067468Snon
7167468Snon#include <sys/param.h>
7267468Snon#include <sys/systm.h>
7367468Snon#include <sys/kernel.h>
7479697Snon
7573025Snon#ifdef __FreeBSD__
7673025Snon#if __FreeBSD_version >= 500001
7767468Snon#include <sys/bio.h>
7879697Snon#else
7979697Snon#include <machine/clock.h>
8073025Snon#endif
8179697Snon#endif	/* __FreeBSD__ */
8279697Snon
8367468Snon#include <sys/buf.h>
8467468Snon#include <sys/queue.h>
8567468Snon#include <sys/malloc.h>
8667468Snon#include <sys/errno.h>
8767468Snon
8879697Snon#ifdef	__NetBSD__
8979697Snon#include <sys/device.h>
9067468Snon#include <vm/vm.h>
9167468Snon
9267468Snon#include <machine/bus.h>
9367468Snon#include <machine/intr.h>
9467468Snon#include <machine/dvcfg.h>
9567468Snon
9667468Snon#include <dev/cons.h>
9767468Snon
9867468Snon#include <dev/scsipi/scsipi_all.h>
9967468Snon#include <dev/scsipi/scsipiconf.h>
10067468Snon#include <dev/scsipi/scsipi_disk.h>
10167468Snon#include <dev/scsipi/scsi_all.h>
10267468Snon#include <dev/scsipi/scsiconf.h>
10379697Snon#include <sys/scsiio.h>
10467468Snon
10567468Snon#include <i386/Cbus/dev/scsi_low.h>
10679697Snon#endif	/* __NetBSD__ */
10779697Snon
10867468Snon#ifdef __FreeBSD__
10967468Snon#include <cam/cam.h>
11067468Snon#include <cam/cam_ccb.h>
11167468Snon#include <cam/cam_sim.h>
11267468Snon#include <cam/cam_debug.h>
11367468Snon#include <cam/cam_periph.h>
114147723Savatar#include <cam/cam_xpt_periph.h>
11567468Snon
11667468Snon#include <cam/scsi/scsi_all.h>
11773025Snon#include <cam/scsi/scsi_message.h>
11867468Snon
11967468Snon#include <cam/scsi/scsi_low.h>
12067468Snon
12167468Snon#include <sys/cons.h>
12279697Snon#endif	/* __FreeBSD__ */
12367468Snon
12479697Snon/**************************************************************
12579697Snon * Constants
12679697Snon **************************************************************/
12779697Snon#define	SCSI_LOW_POLL_HZ	1000
12867468Snon
12979697Snon/* functions return values */
13079697Snon#define	SCSI_LOW_START_NO_QTAG	0
13179697Snon#define	SCSI_LOW_START_QTAG	1
13279697Snon
13367468Snon#define	SCSI_LOW_DONE_COMPLETE	0
13467468Snon#define	SCSI_LOW_DONE_RETRY	1
13567468Snon
13679697Snon/* internal disk flags */
13779697Snon#define	SCSI_LOW_DISK_DISC	0x00000001
13879697Snon#define	SCSI_LOW_DISK_QTAG	0x00000002
13979697Snon#define	SCSI_LOW_DISK_LINK	0x00000004
14079697Snon#define	SCSI_LOW_DISK_PARITY	0x00000008
14179697Snon#define	SCSI_LOW_DISK_SYNC	0x00010000
14279697Snon#define	SCSI_LOW_DISK_WIDE_16	0x00020000
14379697Snon#define	SCSI_LOW_DISK_WIDE_32	0x00040000
14479697Snon#define	SCSI_LOW_DISK_WIDE	(SCSI_LOW_DISK_WIDE_16 | SCSI_LOW_DISK_WIDE_32)
14579697Snon#define	SCSI_LOW_DISK_LFLAGS	0x0000ffff
14679697Snon#define	SCSI_LOW_DISK_TFLAGS	0xffff0000
14779697Snon
148249132Smavstatic MALLOC_DEFINE(M_SCSILOW, "SCSI low", "SCSI low buffers");
149147723Savatar
15079697Snon/**************************************************************
15179697Snon * Declarations
15279697Snon **************************************************************/
15392770Salfred/* static */ void scsi_low_info(struct scsi_low_softc *, struct targ_info *, u_char *);
15492770Salfredstatic void scsi_low_engage(void *);
15592770Salfredstatic struct slccb *scsi_low_establish_ccb(struct targ_info *, struct lun_info *, scsi_low_tag_t);
15692770Salfredstatic int scsi_low_done(struct scsi_low_softc *, struct slccb *);
15792770Salfredstatic int scsi_low_setup_done(struct scsi_low_softc *, struct slccb *);
15892770Salfredstatic void scsi_low_bus_release(struct scsi_low_softc *, struct targ_info *);
15992770Salfredstatic void scsi_low_twiddle_wait(void);
16092770Salfredstatic struct lun_info *scsi_low_alloc_li(struct targ_info *, int, int);
16192770Salfredstatic struct targ_info *scsi_low_alloc_ti(struct scsi_low_softc *, int);
16292770Salfredstatic void scsi_low_calcf_lun(struct lun_info *);
16392770Salfredstatic void scsi_low_calcf_target(struct targ_info *);
16492770Salfredstatic void scsi_low_calcf_show(struct lun_info *);
16592770Salfredstatic void scsi_low_reset_nexus(struct scsi_low_softc *, int);
16692770Salfredstatic void scsi_low_reset_nexus_target(struct scsi_low_softc *, struct targ_info *, int);
16792770Salfredstatic void scsi_low_reset_nexus_lun(struct scsi_low_softc *, struct lun_info *, int);
16892770Salfredstatic int scsi_low_init(struct scsi_low_softc *, u_int);
16992770Salfredstatic void scsi_low_start(struct scsi_low_softc *);
17092770Salfredstatic void scsi_low_free_ti(struct scsi_low_softc *);
17167468Snon
17292770Salfredstatic int scsi_low_alloc_qtag(struct slccb *);
17392770Salfredstatic int scsi_low_dealloc_qtag(struct slccb *);
17492770Salfredstatic int scsi_low_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *, u_int, u_int);
17592770Salfredstatic int scsi_low_message_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, u_int);
17692770Salfredstatic void scsi_low_unit_ready_cmd(struct slccb *);
17792770Salfredstatic void scsi_low_timeout(void *);
17892770Salfredstatic int scsi_low_timeout_check(struct scsi_low_softc *);
17979697Snon#ifdef	SCSI_LOW_START_UP_CHECK
18092770Salfredstatic int scsi_low_start_up(struct scsi_low_softc *);
18179697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
18292770Salfredstatic int scsi_low_abort_ccb(struct scsi_low_softc *, struct slccb *);
18392770Salfredstatic struct slccb *scsi_low_revoke_ccb(struct scsi_low_softc *, struct slccb *, int);
18479697Snon
18579697Snonint scsi_low_version_major = 2;
18679697Snonint scsi_low_version_minor = 17;
18779697Snon
18879697Snonstatic struct scsi_low_softc_tab sl_tab = LIST_HEAD_INITIALIZER(sl_tab);
18979697Snon
19079697Snon/**************************************************************
19179697Snon * Debug, Run test and Statics
19279697Snon **************************************************************/
19379697Snon#ifdef	SCSI_LOW_INFO_DETAIL
19479697Snon#define	SCSI_LOW_INFO(slp, ti, s) scsi_low_info((slp), (ti), (s))
19579697Snon#else	/* !SCSI_LOW_INFO_DETAIL */
19679697Snon#define	SCSI_LOW_INFO(slp, ti, s) printf("%s: %s\n", (slp)->sl_xname, (s))
19779697Snon#endif	/* !SCSI_LOW_INFO_DETAIL */
19879697Snon
19967468Snon#ifdef	SCSI_LOW_STATICS
20089113Smsmithstatic struct scsi_low_statics {
20167468Snon	int nexus_win;
20267468Snon	int nexus_fail;
20367468Snon	int nexus_disconnected;
20467468Snon	int nexus_reselected;
20567468Snon	int nexus_conflict;
20667468Snon} scsi_low_statics;
20767468Snon#endif	/* SCSI_LOW_STATICS */
20879697Snon
20979697Snon#ifdef	SCSI_LOW_DEBUG
21079697Snon#define	SCSI_LOW_DEBUG_DONE	0x00001
21179697Snon#define	SCSI_LOW_DEBUG_DISC	0x00002
21279697Snon#define	SCSI_LOW_DEBUG_SENSE	0x00004
21379697Snon#define	SCSI_LOW_DEBUG_CALCF	0x00008
21479697Snon#define	SCSI_LOW_DEBUG_ACTION	0x10000
21579697Snonint scsi_low_debug = 0;
21679697Snon
21779697Snon#define	SCSI_LOW_MAX_ATTEN_CHECK	32
21879697Snon#define	SCSI_LOW_ATTEN_CHECK	0x0001
21979697Snon#define	SCSI_LOW_CMDLNK_CHECK	0x0002
22079697Snon#define	SCSI_LOW_ABORT_CHECK	0x0004
22179697Snon#define	SCSI_LOW_NEXUS_CHECK	0x0008
22279697Snonint scsi_low_test = 0;
22379697Snonint scsi_low_test_id = 0;
22479697Snon
22592770Salfredstatic void scsi_low_test_abort(struct scsi_low_softc *, struct targ_info *, struct lun_info *);
22692770Salfredstatic void scsi_low_test_cmdlnk(struct scsi_low_softc *, struct slccb *);
22792770Salfredstatic void scsi_low_test_atten(struct scsi_low_softc *, struct targ_info *, u_int);
22879697Snon#define	SCSI_LOW_DEBUG_TEST_GO(fl, id) \
22979697Snon	((scsi_low_test & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
23079697Snon#define	SCSI_LOW_DEBUG_GO(fl, id) \
23179697Snon	((scsi_low_debug & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
23279697Snon#endif	/* SCSI_LOW_DEBUG */
23379697Snon
23467468Snon/**************************************************************
23579697Snon * CCB
23679697Snon **************************************************************/
23779697SnonGENERIC_CCB_STATIC_ALLOC(scsi_low, slccb)
23879697SnonGENERIC_CCB(scsi_low, slccb, ccb_chain)
23979697Snon
24079697Snon/**************************************************************
24179697Snon * Inline functions
24279697Snon **************************************************************/
24379697Snon#define	SCSI_LOW_INLINE	static __inline
24492770SalfredSCSI_LOW_INLINE void scsi_low_activate_qtag(struct slccb *);
24592770SalfredSCSI_LOW_INLINE void scsi_low_deactivate_qtag(struct slccb *);
24692770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_assert(struct slccb *, u_int);
24792770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_exec(struct scsi_low_softc *, struct slccb *);
24892770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_retry(struct slccb *);
24992770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_clear(struct slccb *);
25092770SalfredSCSI_LOW_INLINE void scsi_low_init_msgsys(struct scsi_low_softc *, struct targ_info *);
25179697Snon
25279697SnonSCSI_LOW_INLINE void
25379697Snonscsi_low_activate_qtag(cb)
25479697Snon	struct slccb *cb;
25579697Snon{
25679697Snon	struct lun_info *li = cb->li;
25779697Snon
25879697Snon	if (cb->ccb_tag != SCSI_LOW_UNKTAG)
25979697Snon		return;
26079697Snon
26179697Snon	li->li_nqio ++;
26279697Snon	cb->ccb_tag = cb->ccb_otag;
26379697Snon}
26479697Snon
26579697SnonSCSI_LOW_INLINE void
26679697Snonscsi_low_deactivate_qtag(cb)
26779697Snon	struct slccb *cb;
26879697Snon{
26979697Snon	struct lun_info *li = cb->li;
27079697Snon
27179697Snon	if (cb->ccb_tag == SCSI_LOW_UNKTAG)
27279697Snon		return;
27379697Snon
27479697Snon	li->li_nqio --;
27579697Snon	cb->ccb_tag = SCSI_LOW_UNKTAG;
27679697Snon}
27779697Snon
27879697SnonSCSI_LOW_INLINE void
27979697Snonscsi_low_ccb_message_exec(slp, cb)
28079697Snon	struct scsi_low_softc *slp;
28179697Snon	struct slccb *cb;
28279697Snon{
28379697Snon
28479697Snon	scsi_low_assert_msg(slp, cb->ti, cb->ccb_msgoutflag, 0);
28579697Snon	cb->ccb_msgoutflag = 0;
28679697Snon}
28779697Snon
28879697SnonSCSI_LOW_INLINE void
28979697Snonscsi_low_ccb_message_assert(cb, msg)
29079697Snon	struct slccb *cb;
29179697Snon	u_int msg;
29279697Snon{
29379697Snon
29479697Snon	cb->ccb_msgoutflag = cb->ccb_omsgoutflag = msg;
29579697Snon}
29679697Snon
29779697SnonSCSI_LOW_INLINE void
29879697Snonscsi_low_ccb_message_retry(cb)
29979697Snon	struct slccb *cb;
30079697Snon{
30179697Snon	cb->ccb_msgoutflag = cb->ccb_omsgoutflag;
30279697Snon}
30379697Snon
30479697SnonSCSI_LOW_INLINE void
30579697Snonscsi_low_ccb_message_clear(cb)
30679697Snon	struct slccb *cb;
30779697Snon{
30879697Snon	cb->ccb_msgoutflag = 0;
30979697Snon}
31079697Snon
31179697SnonSCSI_LOW_INLINE void
31279697Snonscsi_low_init_msgsys(slp, ti)
31379697Snon	struct scsi_low_softc *slp;
31479697Snon	struct targ_info *ti;
31579697Snon{
31679697Snon
31779697Snon	ti->ti_msginptr = 0;
31879697Snon	ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0;
31979697Snon	SCSI_LOW_DEASSERT_ATN(slp);
32079697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL);
32179697Snon}
32279697Snon
32379697Snon/*=============================================================
32479697Snon * START OF OS switch  (All OS depend fucntions should be here)
32579697Snon =============================================================*/
32679697Snon/* common os depend utitlities */
32779697Snon#define	SCSI_LOW_CMD_RESIDUAL_CHK	0x0001
32879697Snon#define	SCSI_LOW_CMD_ORDERED_QTAG	0x0002
32979697Snon#define	SCSI_LOW_CMD_ABORT_WARNING	0x0004
33079697Snon
33179697Snonstatic u_int8_t scsi_low_cmd_flags[256] = {
33279697Snon/*	0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
33379697Snon/*0*/	0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0,
33479697Snon/*1*/	0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
33579697Snon/*2*/	0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 5, 5,
33679697Snon/*3*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5,
33779697Snon};
33879697Snon
33979697Snonstruct scsi_low_error_code {
34079697Snon	int error_bits;
34179697Snon	int error_code;
34279697Snon};
34379697Snon
34492770Salfredstatic struct slccb *scsi_low_find_ccb(struct scsi_low_softc *, u_int, u_int, void *);
34592770Salfredstatic int scsi_low_translate_error_code(struct slccb *, struct scsi_low_error_code *);
34679697Snon
34779697Snonstatic struct slccb *
34879697Snonscsi_low_find_ccb(slp, target, lun, osdep)
34979697Snon	struct scsi_low_softc *slp;
35079697Snon	u_int target, lun;
35179697Snon	void *osdep;
35279697Snon{
35379697Snon	struct targ_info *ti;
35479697Snon	struct lun_info *li;
35579697Snon	struct slccb *cb;
35679697Snon
35779697Snon	ti = slp->sl_ti[target];
35879697Snon	li = scsi_low_alloc_li(ti, lun, 0);
35979697Snon	if (li == NULL)
36079697Snon		return NULL;
36179697Snon
36279697Snon	if ((cb = slp->sl_Qnexus) != NULL && cb->osdep == osdep)
36379697Snon		return cb;
36479697Snon
36579697Snon	for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL;
36679697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
36779697Snon	{
36879697Snon		if (cb->osdep == osdep)
36979697Snon			return cb;
37079697Snon	}
37179697Snon
37279697Snon	for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL;
37379697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
37479697Snon	{
37579697Snon		if (cb->osdep == osdep)
37679697Snon			return cb;
37779697Snon	}
37879697Snon	return NULL;
37979697Snon}
38079697Snon
38179697Snonstatic int
38279697Snonscsi_low_translate_error_code(cb, tp)
38379697Snon	struct slccb *cb;
38479697Snon	struct scsi_low_error_code *tp;
38579697Snon{
38679697Snon
38779697Snon	if (cb->ccb_error == 0)
38879697Snon		return tp->error_code;
38979697Snon
39079697Snon	for (tp ++; (cb->ccb_error & tp->error_bits) == 0; tp ++)
39179697Snon		;
39279697Snon	return tp->error_code;
39379697Snon}
39479697Snon
39579697Snon#ifdef SCSI_LOW_INTERFACE_XS
39679697Snon/**************************************************************
39779697Snon * SCSI INTERFACE (XS)
39879697Snon **************************************************************/
39979697Snon#define	SCSI_LOW_MINPHYS		0x10000
400147723Savatar#define	SCSI_LOW_MALLOC(size)		malloc((size), M_SCSILOW, M_NOWAIT)
401147723Savatar#define	SCSI_LOW_FREE(pt)		free((pt), M_SCSILOW)
40279697Snon#define	SCSI_LOW_ALLOC_CCB(flags)	scsi_low_get_ccb((flags))
40379697Snon#define	SCSI_LOW_XS_POLL_HZ		1000
40479697Snon
40592770Salfredstatic int scsi_low_poll_xs(struct scsi_low_softc *, struct slccb *);
40692770Salfredstatic void scsi_low_scsi_minphys_xs(struct buf *);
40779697Snon#ifdef	SCSI_LOW_TARGET_OPEN
40892770Salfredstatic int scsi_low_target_open(struct scsipi_link *, struct cfdata *);
40979697Snon#endif	/* SCSI_LOW_TARGET_OPEN */
41092770Salfredstatic int scsi_low_scsi_cmd_xs(struct scsipi_xfer *);
41192770Salfredstatic int scsi_low_enable_xs(void *, int);
41292770Salfredstatic int scsi_low_ioctl_xs(struct scsipi_link *, u_long, caddr_t, int, struct proc *);
41379697Snon
41492770Salfredstatic int scsi_low_attach_xs(struct scsi_low_softc *);
41592770Salfredstatic int scsi_low_world_start_xs(struct scsi_low_softc *);
41692770Salfredstatic int scsi_low_dettach_xs(struct scsi_low_softc *);
41792770Salfredstatic int scsi_low_ccb_setup_xs(struct scsi_low_softc *, struct slccb *);
41892770Salfredstatic int scsi_low_done_xs(struct scsi_low_softc *, struct slccb *);
41992770Salfredstatic void scsi_low_timeout_xs(struct scsi_low_softc *, int, int);
42092770Salfredstatic u_int scsi_low_translate_quirks_xs(u_int);
42192770Salfredstatic void scsi_low_setup_quirks_xs(struct targ_info *, struct lun_info *, u_int);
42279697Snon
42379697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_xs = {
42479697Snon	scsi_low_attach_xs,
42579697Snon	scsi_low_world_start_xs,
42679697Snon	scsi_low_dettach_xs,
42779697Snon	scsi_low_ccb_setup_xs,
42879697Snon	scsi_low_done_xs,
42979697Snon	scsi_low_timeout_xs
43079697Snon};
43179697Snon
43279697Snonstruct scsipi_device scsi_low_dev = {
43379697Snon	NULL,	/* Use default error handler */
43479697Snon	NULL,	/* have a queue, served by this */
43579697Snon	NULL,	/* have no async handler */
43679697Snon	NULL,	/* Use default 'done' routine */
43779697Snon};
43879697Snon
43979697Snonstruct scsi_low_error_code scsi_low_error_code_xs[] = {
44079697Snon	{0,		XS_NOERROR},
44179697Snon	{SENSEIO,	XS_SENSE},
44279697Snon	{BUSYERR,	XS_BUSY	},
44379697Snon	{SELTIMEOUTIO,	XS_SELTIMEOUT},
44479697Snon	{TIMEOUTIO,	XS_TIMEOUT},
44579697Snon	{-1,		XS_DRIVER_STUFFUP}
44679697Snon};
44779697Snon
44879697Snonstatic int
44979697Snonscsi_low_ioctl_xs(link, cmd, addr, flag, p)
45079697Snon	struct scsipi_link *link;
45179697Snon	u_long cmd;
45279697Snon	caddr_t addr;
45379697Snon	int flag;
45479697Snon	struct proc *p;
45579697Snon{
45679697Snon	struct scsi_low_softc *slp;
45779697Snon	int s, error = ENOTTY;
45879697Snon
45979697Snon	slp = (struct scsi_low_softc *) link->adapter_softc;
46079697Snon	if ((slp->sl_flags & HW_INACTIVE) != 0)
46179697Snon		return ENXIO;
46279697Snon
46379697Snon	if (cmd == SCBUSIORESET)
46479697Snon	{
46579697Snon		s = SCSI_LOW_SPLSCSI();
46679697Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL);
46779697Snon		splx(s);
46879697Snon		error = 0;
46979697Snon	}
47079697Snon	else if (slp->sl_funcs->scsi_low_ioctl != 0)
47179697Snon	{
47279697Snon		error = (*slp->sl_funcs->scsi_low_ioctl)
47379697Snon				(slp, cmd, addr, flag, p);
47479697Snon	}
47579697Snon
47679697Snon	return error;
47779697Snon}
47879697Snon
47979697Snonstatic int
48079697Snonscsi_low_enable_xs(arg, enable)
48179697Snon	void *arg;
48279697Snon	int enable;
48379697Snon{
48479697Snon	struct scsi_low_softc *slp = arg;
48579697Snon
48679697Snon	if (enable != 0)
48779697Snon	{
48879697Snon		if ((slp->sl_flags & HW_INACTIVE) != 0)
48979697Snon			return ENXIO;
49079697Snon	}
49179697Snon	else
49279697Snon	{
49379697Snon		if ((slp->sl_flags & HW_INACTIVE) != 0 ||
49479697Snon		    (slp->sl_flags & HW_POWERCTRL) == 0)
49579697Snon			return 0;
49679697Snon
49779697Snon		slp->sl_flags |= HW_POWDOWN;
49879697Snon		if (slp->sl_funcs->scsi_low_power != NULL)
49979697Snon		{
50079697Snon			(*slp->sl_funcs->scsi_low_power)
50179697Snon					(slp, SCSI_LOW_POWDOWN);
50279697Snon		}
50379697Snon	}
50479697Snon	return 0;
50579697Snon}
50679697Snon
50779697Snonstatic void
50879697Snonscsi_low_scsi_minphys_xs(bp)
50979697Snon	struct buf *bp;
51079697Snon{
51179697Snon
51279697Snon	if (bp->b_bcount > SCSI_LOW_MINPHYS)
51379697Snon		bp->b_bcount = SCSI_LOW_MINPHYS;
51479697Snon	minphys(bp);
51579697Snon}
51679697Snon
51779697Snonstatic int
51879697Snonscsi_low_poll_xs(slp, cb)
51979697Snon	struct scsi_low_softc *slp;
52079697Snon	struct slccb *cb;
52179697Snon{
52279697Snon	struct scsipi_xfer *xs = cb->osdep;
52379697Snon	int tcount;
52479697Snon
52579697Snon	cb->ccb_flags |= CCB_NOSDONE;
52679697Snon	tcount = 0;
52779697Snon
52879697Snon	while (slp->sl_nio > 0)
52979697Snon	{
53079697Snon		SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_XS_POLL_HZ);
53179697Snon
53279697Snon		(*slp->sl_funcs->scsi_low_poll) (slp);
53379697Snon
53479697Snon		if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0)
53579697Snon		{
53679697Snon			cb->ccb_flags |= CCB_NORETRY;
53779697Snon			cb->ccb_error |= FATALIO;
53879697Snon			(void) scsi_low_revoke_ccb(slp, cb, 1);
53979697Snon			printf("%s: hardware inactive in poll mode\n",
54079697Snon				slp->sl_xname);
54179697Snon		}
54279697Snon
54379697Snon		if ((xs->flags & ITSDONE) != 0)
54479697Snon			break;
54579697Snon
54679697Snon		if (tcount ++ < SCSI_LOW_XS_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
54779697Snon			continue;
54879697Snon
54979697Snon		tcount = 0;
55079697Snon		scsi_low_timeout_check(slp);
55179697Snon	}
55279697Snon
55379697Snon	xs->flags |= ITSDONE;
55479697Snon	scsipi_done(xs);
55579697Snon	return COMPLETE;
55679697Snon}
55779697Snon
55879697Snonstatic int
55979697Snonscsi_low_scsi_cmd_xs(xs)
56079697Snon	struct scsipi_xfer *xs;
56179697Snon{
56279697Snon	struct scsipi_link *splp = xs->sc_link;
56379697Snon	struct scsi_low_softc *slp = splp->adapter_softc;
56479697Snon	struct targ_info *ti;
56579697Snon	struct lun_info *li;
56679697Snon	struct slccb *cb;
56779697Snon	int s, targ, lun, flags, rv;
56879697Snon
56979697Snon	if ((cb = SCSI_LOW_ALLOC_CCB(xs->flags & SCSI_NOSLEEP)) == NULL)
57079697Snon		return TRY_AGAIN_LATER;
57179697Snon
57279697Snon	targ = splp->scsipi_scsi.target,
57379697Snon	lun = splp->scsipi_scsi.lun;
57479697Snon	ti = slp->sl_ti[targ];
57579697Snon
57679697Snon	cb->osdep = xs;
57779697Snon	cb->bp = xs->bp;
57879697Snon
57979697Snon	if ((xs->flags & SCSI_POLL) == 0)
58079697Snon		flags = CCB_AUTOSENSE;
58179697Snon	else
58279697Snon		flags = CCB_AUTOSENSE | CCB_POLLED;
58379697Snon
58479697Snon
58579697Snon	s = SCSI_LOW_SPLSCSI();
58679697Snon	li = scsi_low_alloc_li(ti, lun, 1);
58779697Snon	if ((u_int) splp->quirks != li->li_sloi.sloi_quirks)
58879697Snon	{
58979697Snon		scsi_low_setup_quirks_xs(ti, li, (u_int) splp->quirks);
59079697Snon	}
59179697Snon
59279697Snon	if ((xs->flags & SCSI_RESET) != 0)
59379697Snon	{
59479697Snon		flags |= CCB_NORETRY | CCB_URGENT;
59579697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, SCSI_LOW_MSG_RESET);
59679697Snon	}
59779697Snon	else
59879697Snon	{
59979697Snon		if (ti->ti_setup_msg != 0)
60079697Snon		{
60179697Snon			scsi_low_message_enqueue(slp, ti, li, flags);
60279697Snon		}
60379697Snon
60479697Snon		flags |= CCB_SCSIIO;
60579697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, 0);
60679697Snon	}
60779697Snon
60879697Snon#ifdef	SCSI_LOW_DEBUG
60979697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, ti->ti_id) != 0)
61079697Snon	{
61179697Snon		scsi_low_test_abort(slp, ti, li);
61279697Snon	}
61379697Snon#endif	/* SCSI_LOW_DEBUG */
61479697Snon
61579697Snon	if ((cb->ccb_flags & CCB_POLLED) != 0)
61679697Snon	{
61779697Snon		rv = scsi_low_poll_xs(slp, cb);
61879697Snon	}
61979697Snon	else
62079697Snon	{
62179697Snon		rv = SUCCESSFULLY_QUEUED;
62279697Snon	}
62379697Snon	splx(s);
62479697Snon	return rv;
62579697Snon}
62679697Snon
62779697Snonstatic int
62879697Snonscsi_low_attach_xs(slp)
62979697Snon	struct scsi_low_softc *slp;
63079697Snon{
63179697Snon	struct scsipi_adapter *sap;
63279697Snon	struct scsipi_link *splp;
63379697Snon
63479697Snon	strncpy(slp->sl_xname, slp->sl_dev.dv_xname, 16);
63579697Snon
63679697Snon	sap = SCSI_LOW_MALLOC(sizeof(*sap));
63779697Snon	if (sap == NULL)
63879697Snon		return ENOMEM;
63979697Snon	splp = SCSI_LOW_MALLOC(sizeof(*splp));
64079697Snon	if (splp == NULL)
641198356Sbrueffer	{
642198356Sbrueffer		SCSI_LOW_FREE(sap);
64379697Snon		return ENOMEM;
644198356Sbrueffer	}
64579697Snon
64679697Snon	SCSI_LOW_BZERO(sap, sizeof(*sap));
64779697Snon	SCSI_LOW_BZERO(splp, sizeof(*splp));
64879697Snon
64979697Snon	sap->scsipi_cmd = scsi_low_scsi_cmd_xs;
65079697Snon	sap->scsipi_minphys = scsi_low_scsi_minphys_xs;
65179697Snon	sap->scsipi_enable = scsi_low_enable_xs;
65279697Snon	sap->scsipi_ioctl = scsi_low_ioctl_xs;
65379697Snon#ifdef	SCSI_LOW_TARGET_OPEN
65479697Snon	sap->open_target_lu = scsi_low_target_open;
65579697Snon#endif	/* SCSI_LOW_TARGET_OPEN */
65679697Snon
65779697Snon	splp->adapter_softc = slp;
65879697Snon	splp->scsipi_scsi.adapter_target = slp->sl_hostid;
65979697Snon	splp->scsipi_scsi.max_target = slp->sl_ntargs - 1;
66079697Snon	splp->scsipi_scsi.max_lun = slp->sl_nluns - 1;
66179697Snon	splp->scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
66279697Snon	splp->openings = slp->sl_openings;
66379697Snon	splp->type = BUS_SCSI;
66479697Snon	splp->adapter_softc = slp;
66579697Snon	splp->adapter = sap;
66679697Snon	splp->device = &scsi_low_dev;
66779697Snon
66879697Snon	slp->sl_si.si_splp = splp;
66979697Snon	slp->sl_show_result = SHOW_ALL_NEG;
67079697Snon	return 0;
67179697Snon}
67279697Snon
67379697Snonstatic int
67479697Snonscsi_low_world_start_xs(slp)
67579697Snon	struct scsi_low_softc *slp;
67679697Snon{
67779697Snon
67879697Snon	return 0;
67979697Snon}
68079697Snon
68179697Snonstatic int
68279697Snonscsi_low_dettach_xs(slp)
68379697Snon	struct scsi_low_softc *slp;
68479697Snon{
68579697Snon
68679697Snon	/*
68779697Snon	 * scsipi does not have dettach bus fucntion.
68879697Snon	 *
68979697Snon	scsipi_dettach_scsibus(slp->sl_si.si_splp);
69079697Snon	*/
69179697Snon	return 0;
69279697Snon}
69379697Snon
69479697Snonstatic int
69579697Snonscsi_low_ccb_setup_xs(slp, cb)
69679697Snon	struct scsi_low_softc *slp;
69779697Snon	struct slccb *cb;
69879697Snon{
69979697Snon	struct scsipi_xfer *xs = (struct scsipi_xfer *) cb->osdep;
70079697Snon
70179697Snon	if ((cb->ccb_flags & CCB_SCSIIO) != 0)
70279697Snon	{
70379697Snon		cb->ccb_scp.scp_cmd = (u_int8_t *) xs->cmd;
70479697Snon		cb->ccb_scp.scp_cmdlen = xs->cmdlen;
70579697Snon		cb->ccb_scp.scp_data = xs->data;
70679697Snon		cb->ccb_scp.scp_datalen = xs->datalen;
70779697Snon		cb->ccb_scp.scp_direction = (xs->flags & SCSI_DATA_OUT) ?
70879697Snon					SCSI_LOW_WRITE : SCSI_LOW_READ;
70979697Snon		cb->ccb_tcmax = xs->timeout / 1000;
71079697Snon	}
71179697Snon	else
71279697Snon	{
71379697Snon		scsi_low_unit_ready_cmd(cb);
71479697Snon	}
71579697Snon	return SCSI_LOW_START_QTAG;
71679697Snon}
71779697Snon
71879697Snonstatic int
71979697Snonscsi_low_done_xs(slp, cb)
72079697Snon	struct scsi_low_softc *slp;
72179697Snon	struct slccb *cb;
72279697Snon{
72379697Snon	struct scsipi_xfer *xs;
72479697Snon
72579697Snon	xs = (struct scsipi_xfer *) cb->osdep;
72679697Snon	if (cb->ccb_error == 0)
72779697Snon	{
72879697Snon		xs->error = XS_NOERROR;
72979697Snon		xs->resid = 0;
73079697Snon	}
73179697Snon	else
73279697Snon	{
73379697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
73479697Snon			cb->ccb_error |= ABORTIO;
73579697Snon
73679697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
73779697Snon		    (cb->ccb_error & ABORTIO) == 0)
73879697Snon			return EJUSTRETURN;
73979697Snon
74079697Snon		if ((cb->ccb_error & SENSEIO) != 0)
74179697Snon		{
74279697Snon			xs->sense.scsi_sense = cb->ccb_sense;
74379697Snon		}
74479697Snon
74579697Snon		xs->error = scsi_low_translate_error_code(cb,
74679697Snon				&scsi_low_error_code_xs[0]);
74779697Snon
74879697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
74979697Snon		if ((cb->ccb_flags & CCB_SILENT) == 0 &&
75079697Snon		    cb->ccb_scp.scp_cmdlen > 0 &&
75179697Snon		    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
75279697Snon		     SCSI_LOW_CMD_ABORT_WARNING) != 0)
75379697Snon		{
75479697Snon			printf("%s: WARNING: scsi_low IO abort\n",
75579697Snon				slp->sl_xname);
75679697Snon			scsi_low_print(slp, NULL);
75779697Snon		}
75879697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
75979697Snon	}
76079697Snon
76179697Snon	if (cb->ccb_scp.scp_status == ST_UNKNOWN)
76279697Snon		xs->status = 0;	/* XXX */
76379697Snon	else
76479697Snon		xs->status = cb->ccb_scp.scp_status;
76579697Snon
76679697Snon	xs->flags |= ITSDONE;
76779697Snon	if ((cb->ccb_flags & CCB_NOSDONE) == 0)
76879697Snon		scsipi_done(xs);
76979697Snon
77079697Snon	return 0;
77179697Snon}
77279697Snon
77379697Snonstatic void
77479697Snonscsi_low_timeout_xs(slp, ch, action)
77579697Snon	struct scsi_low_softc *slp;
77679697Snon	int ch;
77779697Snon	int action;
77879697Snon{
77979697Snon
78079697Snon	switch (ch)
78179697Snon	{
78279697Snon	case SCSI_LOW_TIMEOUT_CH_IO:
78379697Snon		switch (action)
78479697Snon		{
78579697Snon		case SCSI_LOW_TIMEOUT_START:
78679697Snon			timeout(scsi_low_timeout, slp,
78779697Snon				hz / SCSI_LOW_TIMEOUT_HZ);
78879697Snon			break;
78979697Snon		case SCSI_LOW_TIMEOUT_STOP:
79079697Snon			untimeout(scsi_low_timeout, slp);
79179697Snon			break;
79279697Snon		}
79379697Snon		break;
79479697Snon
79579697Snon	case SCSI_LOW_TIMEOUT_CH_ENGAGE:
79679697Snon		switch (action)
79779697Snon		{
79879697Snon		case SCSI_LOW_TIMEOUT_START:
79979697Snon			timeout(scsi_low_engage, slp, 1);
80079697Snon			break;
80179697Snon		case SCSI_LOW_TIMEOUT_STOP:
80279697Snon			untimeout(scsi_low_engage, slp);
80379697Snon			break;
80479697Snon		}
80579697Snon		break;
80679697Snon
80779697Snon	case SCSI_LOW_TIMEOUT_CH_RECOVER:
80879697Snon		break;
80979697Snon	}
81079697Snon}
81179697Snon
81279697Snonu_int
81379697Snonscsi_low_translate_quirks_xs(quirks)
81479697Snon	u_int quirks;
81579697Snon{
81679697Snon	u_int flags;
81779697Snon
81879697Snon	flags = SCSI_LOW_DISK_LFLAGS | SCSI_LOW_DISK_TFLAGS;
81979697Snon
82079697Snon#ifdef	SDEV_NODISC
82179697Snon	if (quirks & SDEV_NODISC)
82279697Snon		flags &= ~SCSI_LOW_DISK_DISC;
82379697Snon#endif	/* SDEV_NODISC */
82479697Snon#ifdef	SDEV_NOPARITY
82579697Snon	if (quirks & SDEV_NOPARITY)
82679697Snon		flags &= ~SCSI_LOW_DISK_PARITY;
82779697Snon#endif	/* SDEV_NOPARITY */
82879697Snon#ifdef	SDEV_NOCMDLNK
82979697Snon	if (quirks & SDEV_NOCMDLNK)
83079697Snon		flags &= ~SCSI_LOW_DISK_LINK;
83179697Snon#endif	/* SDEV_NOCMDLNK */
83279697Snon#ifdef	SDEV_NOTAG
83379697Snon	if (quirks & SDEV_NOTAG)
83479697Snon		flags &= ~SCSI_LOW_DISK_QTAG;
83579697Snon#endif	/* SDEV_NOTAG */
83679697Snon#ifdef	SDEV_NOSYNC
83779697Snon	if (quirks & SDEV_NOSYNC)
83879697Snon		flags &= ~SCSI_LOW_DISK_SYNC;
83979697Snon#endif	/* SDEV_NOSYNC */
84079697Snon
84179697Snon	return flags;
84279697Snon}
84379697Snon
84479697Snonstatic void
84579697Snonscsi_low_setup_quirks_xs(ti, li, flags)
84679697Snon	struct targ_info *ti;
84779697Snon	struct lun_info *li;
84879697Snon	u_int flags;
84979697Snon{
85079697Snon	u_int quirks;
85179697Snon
85279697Snon	li->li_sloi.sloi_quirks = flags;
85379697Snon	quirks = scsi_low_translate_quirks_xs(flags);
85479697Snon	ti->ti_quirks = quirks & SCSI_LOW_DISK_TFLAGS;
85579697Snon	li->li_quirks = quirks & SCSI_LOW_DISK_LFLAGS;
85679697Snon	ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
85779697Snon	li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
85879697Snon	scsi_low_calcf_target(ti);
85979697Snon	scsi_low_calcf_lun(li);
86079697Snon	scsi_low_calcf_show(li);
86179697Snon}
86279697Snon
86379697Snon#ifdef	SCSI_LOW_TARGET_OPEN
86479697Snonstatic int
86579697Snonscsi_low_target_open(link, cf)
86679697Snon	struct scsipi_link *link;
86779697Snon	struct cfdata *cf;
86879697Snon{
86979697Snon	u_int target = link->scsipi_scsi.target;
87079697Snon	u_int lun = link->scsipi_scsi.lun;
87179697Snon	struct scsi_low_softc *slp;
87279697Snon	struct targ_info *ti;
87379697Snon	struct lun_info *li;
87479697Snon
87579697Snon	slp = (struct scsi_low_softc *) link->adapter_softc;
87679697Snon	ti = slp->sl_ti[target];
87779697Snon	li = scsi_low_alloc_li(ti, lun, 0);
87879697Snon	if (li == NULL)
87979697Snon		return 0;
88079697Snon
88179697Snon	li->li_cfgflags = cf->cf_flags;
88279697Snon	scsi_low_setup_quirks_xs(ti, li, (u_int) link->quirks);
88379697Snon	return 0;
88479697Snon}
88579697Snon#endif	/* SCSI_LOW_TARGET_OPEN */
88679697Snon
88779697Snon#endif	/* SCSI_LOW_INTERFACE_XS */
88879697Snon
88979697Snon#ifdef SCSI_LOW_INTERFACE_CAM
89079697Snon/**************************************************************
89179697Snon * SCSI INTERFACE (CAM)
89279697Snon **************************************************************/
893147723Savatar#define	SCSI_LOW_MALLOC(size)		malloc((size), M_SCSILOW, M_NOWAIT)
894147723Savatar#define	SCSI_LOW_FREE(pt)		free((pt), M_SCSILOW)
89579697Snon#define	SCSI_LOW_ALLOC_CCB(flags)	scsi_low_get_ccb()
89679697Snon
89792770Salfredstatic void scsi_low_poll_cam(struct cam_sim *);
89892770Salfredvoid scsi_low_scsi_action_cam(struct cam_sim *, union ccb *);
89979697Snon
90092770Salfredstatic int scsi_low_attach_cam(struct scsi_low_softc *);
90192770Salfredstatic int scsi_low_world_start_cam(struct scsi_low_softc *);
90292770Salfredstatic int scsi_low_dettach_cam(struct scsi_low_softc *);
90392770Salfredstatic int scsi_low_ccb_setup_cam(struct scsi_low_softc *, struct slccb *);
90492770Salfredstatic int scsi_low_done_cam(struct scsi_low_softc *, struct slccb *);
90592770Salfredstatic void scsi_low_timeout_cam(struct scsi_low_softc *, int, int);
90679697Snon
90779697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_cam = {
90879697Snon	scsi_low_attach_cam,
90979697Snon	scsi_low_world_start_cam,
91079697Snon	scsi_low_dettach_cam,
91179697Snon	scsi_low_ccb_setup_cam,
91279697Snon	scsi_low_done_cam,
91379697Snon	scsi_low_timeout_cam
91479697Snon};
91579697Snon
91679697Snonstruct scsi_low_error_code scsi_low_error_code_cam[] = {
91779697Snon	{0,			CAM_REQ_CMP},
91879697Snon	{SENSEIO, 		CAM_AUTOSNS_VALID | CAM_REQ_CMP_ERR},
91979697Snon	{SENSEERR,		CAM_AUTOSENSE_FAIL},
92079697Snon	{UACAERR,		CAM_SCSI_STATUS_ERROR},
92179697Snon	{BUSYERR | STATERR,	CAM_SCSI_STATUS_ERROR},
92279697Snon	{SELTIMEOUTIO,		CAM_SEL_TIMEOUT},
92379697Snon	{TIMEOUTIO,		CAM_CMD_TIMEOUT},
92479697Snon	{PDMAERR,		CAM_DATA_RUN_ERR},
92579697Snon	{PARITYERR,		CAM_UNCOR_PARITY},
92679697Snon	{UBFERR,		CAM_UNEXP_BUSFREE},
92779697Snon	{ABORTIO,		CAM_REQ_ABORTED},
92879697Snon	{-1,			CAM_UNREC_HBA_ERROR}
92979697Snon};
93079697Snon
93179697Snon#define	SIM2SLP(sim)	((struct scsi_low_softc *) cam_sim_softc((sim)))
93279697Snon
93379697Snon/* XXX:
93479697Snon * Please check a polling hz, currently we assume scsi_low_poll() is
93579697Snon * called each 1 ms.
93679697Snon */
93779697Snon#define	SCSI_LOW_CAM_POLL_HZ	1000	/* OK ? */
93879697Snon
93979697Snonstatic void
94079697Snonscsi_low_poll_cam(sim)
94179697Snon	struct cam_sim *sim;
94279697Snon{
94379697Snon	struct scsi_low_softc *slp = SIM2SLP(sim);
94479697Snon
94579697Snon	(*slp->sl_funcs->scsi_low_poll) (slp);
94679697Snon
94779697Snon	if (slp->sl_si.si_poll_count ++ >=
94879697Snon	    SCSI_LOW_CAM_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
94979697Snon	{
95079697Snon		slp->sl_si.si_poll_count = 0;
95179697Snon		scsi_low_timeout_check(slp);
95279697Snon	}
95379697Snon}
95479697Snon
95579697Snonvoid
95679697Snonscsi_low_scsi_action_cam(sim, ccb)
95779697Snon	struct cam_sim *sim;
95879697Snon	union ccb *ccb;
95979697Snon{
96079697Snon	struct scsi_low_softc *slp = SIM2SLP(sim);
96179697Snon	struct targ_info *ti;
96279697Snon	struct lun_info *li;
96379697Snon	struct slccb *cb;
96479697Snon	u_int lun, flags, msg, target;
96579697Snon	int s, rv;
96679697Snon
96779697Snon	target = (u_int) (ccb->ccb_h.target_id);
96879697Snon	lun = (u_int) ccb->ccb_h.target_lun;
96979697Snon
97079697Snon#ifdef	SCSI_LOW_DEBUG
97179697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_ACTION, target) != 0)
97279697Snon	{
97379697Snon		printf("%s: cam_action: func code 0x%x target: %d, lun: %d\n",
97479697Snon			slp->sl_xname, ccb->ccb_h.func_code, target, lun);
97579697Snon	}
97679697Snon#endif	/* SCSI_LOW_DEBUG */
97779697Snon
97879697Snon	switch (ccb->ccb_h.func_code) {
97979697Snon	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
98079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
98179697Snon		if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
98279697Snon		{
98379697Snon			printf("%s: invalid target/lun\n", slp->sl_xname);
98479697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
98579697Snon			xpt_done(ccb);
98679697Snon			return;
98779697Snon		}
98879697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
98979697Snon
99079697Snon		if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) {
99179697Snon			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
99279697Snon			xpt_done(ccb);
99379697Snon			return;
99479697Snon		}
99579697Snon
99679697Snon		ti = slp->sl_ti[target];
99779697Snon		cb->osdep = ccb;
99879697Snon		cb->bp = NULL;
99979697Snon		if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
100079697Snon			flags = CCB_AUTOSENSE | CCB_SCSIIO;
100179697Snon		else
100279697Snon			flags = CCB_SCSIIO;
100379697Snon
100479697Snon		s = SCSI_LOW_SPLSCSI();
100579697Snon		li = scsi_low_alloc_li(ti, lun, 1);
100679697Snon
100779697Snon		if (ti->ti_setup_msg != 0)
100879697Snon		{
100979697Snon			scsi_low_message_enqueue(slp, ti, li, CCB_AUTOSENSE);
101079697Snon		}
101179697Snon
101279697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, 0);
101379697Snon
101479697Snon#ifdef	SCSI_LOW_DEBUG
101579697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, target) != 0)
101679697Snon		{
101779697Snon			scsi_low_test_abort(slp, ti, li);
101879697Snon		}
101979697Snon#endif	/* SCSI_LOW_DEBUG */
102079697Snon		splx(s);
102179697Snon		break;
102279697Snon
102379697Snon	case XPT_EN_LUN:		/* Enable LUN as a target */
102479697Snon	case XPT_TARGET_IO:		/* Execute target I/O request */
102579697Snon	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
102679697Snon	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
102779697Snon		/* XXX Implement */
102879697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
102979697Snon		xpt_done(ccb);
103079697Snon		break;
103179697Snon
103279697Snon	case XPT_ABORT:			/* Abort the specified CCB */
103379697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
103479697Snon		if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
103579697Snon		{
103679697Snon			printf("%s: invalid target/lun\n", slp->sl_xname);
103779697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
103879697Snon			xpt_done(ccb);
103979697Snon			return;
104079697Snon		}
104179697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
104279697Snon
104379697Snon		s = SCSI_LOW_SPLSCSI();
104479697Snon		cb = scsi_low_find_ccb(slp, target, lun, ccb->cab.abort_ccb);
104579697Snon		rv = scsi_low_abort_ccb(slp, cb);
104679697Snon		splx(s);
104779697Snon
104879697Snon		if (rv == 0)
104979697Snon			ccb->ccb_h.status = CAM_REQ_CMP;
105079697Snon		else
105179697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
105279697Snon		xpt_done(ccb);
105379697Snon		break;
105479697Snon
105579697Snon	case XPT_SET_TRAN_SETTINGS: {
1056163816Smjacob		struct ccb_trans_settings_scsi *scsi;
1057163816Smjacob        	struct ccb_trans_settings_spi *spi;
105879697Snon		struct ccb_trans_settings *cts;
105979697Snon		u_int val;
106079697Snon
106179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
106279697Snon		if (target == CAM_TARGET_WILDCARD)
106379697Snon		{
106479697Snon			printf("%s: invalid target\n", slp->sl_xname);
106579697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
106679697Snon			xpt_done(ccb);
106779697Snon			return;
106879697Snon		}
106979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
107079697Snon		cts = &ccb->cts;
107179697Snon		ti = slp->sl_ti[target];
107279697Snon		if (lun == CAM_LUN_WILDCARD)
107379697Snon			lun = 0;
107479697Snon
107579697Snon		s = SCSI_LOW_SPLSCSI();
1076163816Smjacob		scsi = &cts->proto_specific.scsi;
1077163816Smjacob		spi = &cts->xport_specific.spi;
1078163816Smjacob		if ((spi->valid & (CTS_SPI_VALID_BUS_WIDTH |
1079163816Smjacob				   CTS_SPI_VALID_SYNC_RATE |
1080163816Smjacob				   CTS_SPI_VALID_SYNC_OFFSET)) != 0)
1081163816Smjacob		{
1082163816Smjacob			if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) {
1083163816Smjacob				val = spi->bus_width;
1084163816Smjacob				if (val < ti->ti_width)
1085163816Smjacob					ti->ti_width = val;
1086163816Smjacob			}
1087163816Smjacob			if (spi->valid & CTS_SPI_VALID_SYNC_RATE) {
1088163816Smjacob				val = spi->sync_period;
1089163816Smjacob				if (val == 0 || val > ti->ti_maxsynch.period)
1090163816Smjacob					ti->ti_maxsynch.period = val;
1091163816Smjacob			}
1092163816Smjacob			if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) {
1093163816Smjacob				val = spi->sync_offset;
1094163816Smjacob				if (val < ti->ti_maxsynch.offset)
1095163816Smjacob					ti->ti_maxsynch.offset = val;
1096163816Smjacob			}
1097163816Smjacob			ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
1098163816Smjacob			scsi_low_calcf_target(ti);
1099163816Smjacob		}
1100163816Smjacob
1101163816Smjacob		if ((spi->valid & CTS_SPI_FLAGS_DISC_ENB) != 0 ||
1102163816Smjacob                    (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
1103163816Smjacob
1104163816Smjacob			li = scsi_low_alloc_li(ti, lun, 1);
1105163816Smjacob			if (spi->valid & CTS_SPI_FLAGS_DISC_ENB) {
1106163816Smjacob				li->li_quirks |= SCSI_LOW_DISK_DISC;
1107163816Smjacob			} else {
1108163816Smjacob				li->li_quirks &= ~SCSI_LOW_DISK_DISC;
1109163816Smjacob			}
1110163816Smjacob
1111163816Smjacob			if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) {
1112163816Smjacob				li->li_quirks |= SCSI_LOW_DISK_QTAG;
1113163816Smjacob			} else {
1114163816Smjacob				li->li_quirks &= ~SCSI_LOW_DISK_QTAG;
1115163816Smjacob			}
1116163816Smjacob			li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
1117163816Smjacob			scsi_low_calcf_target(ti);
1118163816Smjacob			scsi_low_calcf_lun(li);
1119163816Smjacob			if ((slp->sl_show_result & SHOW_CALCF_RES) != 0)
1120163816Smjacob				scsi_low_calcf_show(li);
1121163816Smjacob		}
112279697Snon		splx(s);
112379697Snon
112479697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
112579697Snon		xpt_done(ccb);
112679697Snon		break;
112779697Snon	}
112879697Snon
112979697Snon	case XPT_GET_TRAN_SETTINGS: {
113079697Snon		struct ccb_trans_settings *cts;
113179697Snon		u_int diskflags;
113279697Snon
113379697Snon		cts = &ccb->cts;
113479697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
113579697Snon		if (target == CAM_TARGET_WILDCARD)
113679697Snon		{
113779697Snon			printf("%s: invalid target\n", slp->sl_xname);
113879697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
113979697Snon			xpt_done(ccb);
114079697Snon			return;
114179697Snon		}
114279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
114379697Snon		ti = slp->sl_ti[target];
114479697Snon		if (lun == CAM_LUN_WILDCARD)
114579697Snon			lun = 0;
114679697Snon
114779697Snon		s = SCSI_LOW_SPLSCSI();
114879697Snon		li = scsi_low_alloc_li(ti, lun, 1);
114979697Snon		if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) {
115079697Snon			struct ccb_trans_settings_scsi *scsi =
115179697Snon				&cts->proto_specific.scsi;
115279697Snon			struct ccb_trans_settings_spi *spi =
115379697Snon				&cts->xport_specific.spi;
115479697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
115579697Snon			if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID)
115679697Snon			{
115779697Snon				ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
115879697Snon				printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n",
115979697Snon					slp->sl_xname);
116079697Snon				goto settings_out;
116179697Snon			}
116279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
116379697Snon			cts->protocol = PROTO_SCSI;
116479697Snon			cts->protocol_version = SCSI_REV_2;
116579697Snon			cts->transport = XPORT_SPI;
116679697Snon			cts->transport_version = 2;
116779697Snon
116879697Snon			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
116979697Snon			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
117079697Snon
117179697Snon			diskflags = li->li_diskflags & li->li_cfgflags;
117279697Snon			if (diskflags & SCSI_LOW_DISK_DISC)
117379697Snon				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
117479697Snon			if (diskflags & SCSI_LOW_DISK_QTAG)
117579697Snon				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
117679697Snon
117779697Snon			spi->sync_period = ti->ti_maxsynch.period;
117879697Snon			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
117979697Snon			spi->sync_offset = ti->ti_maxsynch.offset;
118079697Snon			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
118179697Snon
118279697Snon			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
118379697Snon			spi->bus_width = ti->ti_width;
118479697Snon
118579697Snon			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
118679697Snon				scsi->valid = CTS_SCSI_VALID_TQ;
118779697Snon				spi->valid |= CTS_SPI_VALID_DISC;
118879697Snon			} else
118979697Snon				scsi->valid = 0;
119079697Snon		} else
119179697Snon			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
119279697Snonsettings_out:
119379697Snon		splx(s);
119479697Snon		xpt_done(ccb);
119579697Snon		break;
119679697Snon	}
119779697Snon
119879697Snon	case XPT_CALC_GEOMETRY: { /* not yet HN2 */
1199116351Snjl		cam_calc_geometry(&ccb->ccg, /*extended*/1);
120079697Snon		xpt_done(ccb);
120179697Snon		break;
120279697Snon	}
120379697Snon
120479697Snon	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
120579697Snon		s = SCSI_LOW_SPLSCSI();
120679697Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL);
120779697Snon		splx(s);
120879697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
120979697Snon		xpt_done(ccb);
121079697Snon		break;
121179697Snon
121279697Snon	case XPT_TERM_IO:	/* Terminate the I/O process */
121379697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
121479697Snon		xpt_done(ccb);
121579697Snon		break;
121679697Snon
121779697Snon	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
121879697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
121979697Snon		if (target == CAM_TARGET_WILDCARD)
122079697Snon		{
122179697Snon			printf("%s: invalid target\n", slp->sl_xname);
122279697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
122379697Snon			xpt_done(ccb);
122479697Snon			return;
122579697Snon		}
122679697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
122779697Snon
122879697Snon		msg = SCSI_LOW_MSG_RESET;
122979697Snon		if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL))
123079697Snon		{
123179697Snon			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
123279697Snon			xpt_done(ccb);
123379697Snon			return;
123479697Snon		}
123579697Snon
123679697Snon		ti = slp->sl_ti[target];
123779697Snon		if (lun == CAM_LUN_WILDCARD)
123879697Snon			lun = 0;
123979697Snon		cb->osdep = ccb;
124079697Snon		cb->bp = NULL;
124179697Snon		if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
124279697Snon			flags = CCB_AUTOSENSE | CCB_NORETRY | CCB_URGENT;
124379697Snon		else
124479697Snon			flags = CCB_NORETRY | CCB_URGENT;
124579697Snon
124679697Snon		s = SCSI_LOW_SPLSCSI();
124779697Snon		li = scsi_low_alloc_li(ti, lun, 1);
124879697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, msg);
124979697Snon		splx(s);
125079697Snon		break;
125179697Snon
125279697Snon	case XPT_PATH_INQ: {		/* Path routing inquiry */
125379697Snon		struct ccb_pathinq *cpi = &ccb->cpi;
125479697Snon
125579697Snon		cpi->version_num = scsi_low_version_major;
125679697Snon		cpi->hba_inquiry = PI_TAG_ABLE | PI_LINKED_CDB;
125779697Snon		ti = slp->sl_ti[slp->sl_hostid];	/* host id */
125879697Snon		if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
125979697Snon			cpi->hba_inquiry |= PI_WIDE_16;
126079697Snon		if (ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
126179697Snon			cpi->hba_inquiry |= PI_WIDE_32;
126279697Snon		if (ti->ti_maxsynch.offset > 0)
126379697Snon			cpi->hba_inquiry |= PI_SDTR_ABLE;
126479697Snon		cpi->target_sprt = 0;
126579697Snon		cpi->hba_misc = 0;
126679697Snon		cpi->hba_eng_cnt = 0;
126779697Snon		cpi->max_target = slp->sl_ntargs - 1;
126879697Snon		cpi->max_lun = slp->sl_nluns - 1;
126979697Snon		cpi->initiator_id = slp->sl_hostid;
127079697Snon		cpi->bus_id = cam_sim_bus(sim);
127179697Snon		cpi->base_transfer_speed = 3300;
127279697Snon		cpi->transport = XPORT_SPI;
127379697Snon		cpi->transport_version = 2;
127479697Snon		cpi->protocol = PROTO_SCSI;
127579697Snon		cpi->protocol_version = SCSI_REV_2;
127679697Snon		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
127779697Snon		strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN);
127879697Snon		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
127979697Snon		cpi->unit_number = cam_sim_unit(sim);
128079697Snon		cpi->ccb_h.status = CAM_REQ_CMP;
128179697Snon		xpt_done(ccb);
128279697Snon		break;
128379697Snon	}
128479697Snon
128579697Snon	default:
128679697Snon	        printf("scsi_low: non support func_code = %d ",
128779697Snon			ccb->ccb_h.func_code);
128879697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
128979697Snon		xpt_done(ccb);
129079697Snon		break;
129179697Snon	}
129279697Snon}
129379697Snon
129479697Snonstatic int
129579697Snonscsi_low_attach_cam(slp)
129679697Snon	struct scsi_low_softc *slp;
129779697Snon{
129879697Snon	struct cam_devq *devq;
129979697Snon	int tagged_openings;
130079697Snon
130179697Snon	sprintf(slp->sl_xname, "%s%d",
130279697Snon		DEVPORT_DEVNAME(slp->sl_dev), DEVPORT_DEVUNIT(slp->sl_dev));
130379697Snon
130479697Snon	devq = cam_simq_alloc(SCSI_LOW_NCCB);
130579697Snon	if (devq == NULL)
130679697Snon		return (ENOMEM);
130779697Snon
130879697Snon	/*
130979697Snon	 * ask the adapter what subunits are present
131079697Snon	 */
131179697Snon	tagged_openings = min(slp->sl_openings, SCSI_LOW_MAXNEXUS);
131279697Snon	slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam,
131379697Snon				scsi_low_poll_cam,
131479697Snon				DEVPORT_DEVNAME(slp->sl_dev), slp,
1315168752Sscottl				DEVPORT_DEVUNIT(slp->sl_dev), &Giant,
131679697Snon				slp->sl_openings, tagged_openings, devq);
131779697Snon
131879697Snon	if (slp->sl_si.sim == NULL) {
131979697Snon		cam_simq_free(devq);
132079697Snon	 	return ENODEV;
132179697Snon	}
132279697Snon
1323170872Sscottl	if (xpt_bus_register(slp->sl_si.sim, NULL, 0) != CAM_SUCCESS) {
1324147723Savatar		free(slp->sl_si.sim, M_SCSILOW);
132579697Snon	 	return ENODEV;
132679697Snon	}
132779697Snon
132879697Snon	if (xpt_create_path(&slp->sl_si.path, /*periph*/NULL,
132979697Snon			cam_sim_path(slp->sl_si.sim), CAM_TARGET_WILDCARD,
133079697Snon			CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
133179697Snon		xpt_bus_deregister(cam_sim_path(slp->sl_si.sim));
133279697Snon		cam_sim_free(slp->sl_si.sim, /*free_simq*/TRUE);
133379697Snon		return ENODEV;
133479697Snon	}
133579697Snon
133679697Snon	slp->sl_show_result = SHOW_CALCF_RES;		/* OK ? */
133779697Snon	return 0;
133879697Snon}
133979697Snon
134079697Snonstatic int
134179697Snonscsi_low_world_start_cam(slp)
134279697Snon	struct scsi_low_softc *slp;
134379697Snon{
134479697Snon
134579697Snon	return 0;
134679697Snon}
134779697Snon
134879697Snonstatic int
134979697Snonscsi_low_dettach_cam(slp)
135079697Snon	struct scsi_low_softc *slp;
135179697Snon{
135279697Snon
135379697Snon	xpt_async(AC_LOST_DEVICE, slp->sl_si.path, NULL);
135479697Snon	xpt_free_path(slp->sl_si.path);
135579697Snon	xpt_bus_deregister(cam_sim_path(slp->sl_si.sim));
135679697Snon	cam_sim_free(slp->sl_si.sim, /* free_devq */ TRUE);
135779697Snon	return 0;
135879697Snon}
135979697Snon
136079697Snonstatic int
136179697Snonscsi_low_ccb_setup_cam(slp, cb)
136279697Snon	struct scsi_low_softc *slp;
136379697Snon	struct slccb *cb;
136479697Snon{
136579697Snon        union ccb *ccb = (union ccb *) cb->osdep;
136679697Snon
136779697Snon	if ((cb->ccb_flags & CCB_SCSIIO) != 0)
136879697Snon	{
136979697Snon		cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes;
137079697Snon		cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len;
137179697Snon		cb->ccb_scp.scp_data = ccb->csio.data_ptr;
137279697Snon		cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len;
137379697Snon		if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
137479697Snon			cb->ccb_scp.scp_direction = SCSI_LOW_WRITE;
137579697Snon		else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */
137679697Snon			cb->ccb_scp.scp_direction = SCSI_LOW_READ;
137779697Snon		cb->ccb_tcmax = ccb->ccb_h.timeout / 1000;
137879697Snon	}
137979697Snon	else
138079697Snon	{
138179697Snon		scsi_low_unit_ready_cmd(cb);
138279697Snon	}
138379697Snon	return SCSI_LOW_START_QTAG;
138479697Snon}
138579697Snon
138679697Snonstatic int
138779697Snonscsi_low_done_cam(slp, cb)
138879697Snon	struct scsi_low_softc *slp;
138979697Snon	struct slccb *cb;
139079697Snon{
139179697Snon	union ccb *ccb;
139279697Snon
139379697Snon	ccb = (union ccb *) cb->osdep;
139479697Snon	if (cb->ccb_error == 0)
139579697Snon	{
139679697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
139779697Snon		ccb->csio.resid = 0;
139879697Snon	}
139979697Snon	else
140079697Snon	{
140179697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
140279697Snon			cb->ccb_error |= ABORTIO;
140379697Snon
140479697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
140579697Snon		    (cb->ccb_error & ABORTIO) == 0)
140679697Snon			return EJUSTRETURN;
140779697Snon
140879697Snon		if ((cb->ccb_error & SENSEIO) != 0)
140979697Snon		{
141079697Snon			memcpy(&ccb->csio.sense_data,
141179697Snon			       &cb->ccb_sense,
141279697Snon			       sizeof(ccb->csio.sense_data));
141379697Snon		}
141479697Snon
141579697Snon		ccb->ccb_h.status = scsi_low_translate_error_code(cb,
141679697Snon					&scsi_low_error_code_cam[0]);
141779697Snon
141879697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
141979697Snon		if ((cb->ccb_flags & CCB_SILENT) == 0 &&
142079697Snon		    cb->ccb_scp.scp_cmdlen > 0 &&
142179697Snon		    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
142279697Snon		     SCSI_LOW_CMD_ABORT_WARNING) != 0)
142379697Snon		{
142479697Snon			printf("%s: WARNING: scsi_low IO abort\n",
142579697Snon				slp->sl_xname);
142679697Snon			scsi_low_print(slp, NULL);
142779697Snon		}
142879697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
142979697Snon	}
143079697Snon
143179697Snon	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0)
143279697Snon		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
143379697Snon
143479697Snon	if (cb->ccb_scp.scp_status == ST_UNKNOWN)
143579697Snon		ccb->csio.scsi_status = 0;	/* XXX */
143679697Snon	else
143779697Snon		ccb->csio.scsi_status = cb->ccb_scp.scp_status;
143879697Snon
143979697Snon	if ((cb->ccb_flags & CCB_NOSDONE) == 0)
144079697Snon		xpt_done(ccb);
144179697Snon	return 0;
144279697Snon}
144379697Snon
144479697Snonstatic void
144579697Snonscsi_low_timeout_cam(slp, ch, action)
144679697Snon	struct scsi_low_softc *slp;
144779697Snon	int ch;
144879697Snon	int action;
144979697Snon{
145079697Snon
145179697Snon	switch (ch)
145279697Snon	{
145379697Snon	case SCSI_LOW_TIMEOUT_CH_IO:
145479697Snon		switch (action)
145579697Snon		{
145679697Snon		case SCSI_LOW_TIMEOUT_START:
145779697Snon			slp->sl_si.timeout_ch = timeout(scsi_low_timeout, slp,
145879697Snon				hz / SCSI_LOW_TIMEOUT_HZ);
145979697Snon			break;
146079697Snon		case SCSI_LOW_TIMEOUT_STOP:
146179697Snon			untimeout(scsi_low_timeout, slp, slp->sl_si.timeout_ch);
146279697Snon			break;
146379697Snon		}
146479697Snon		break;
146579697Snon
146679697Snon	case SCSI_LOW_TIMEOUT_CH_ENGAGE:
146779697Snon		switch (action)
146879697Snon		{
146979697Snon		case SCSI_LOW_TIMEOUT_START:
147079697Snon			slp->sl_si.engage_ch = timeout(scsi_low_engage, slp, 1);
147179697Snon			break;
147279697Snon		case SCSI_LOW_TIMEOUT_STOP:
147379697Snon			untimeout(scsi_low_engage, slp, slp->sl_si.engage_ch);
147479697Snon			break;
147579697Snon		}
147679697Snon		break;
147779697Snon	case SCSI_LOW_TIMEOUT_CH_RECOVER:
147879697Snon		break;
147979697Snon	}
148079697Snon}
148179697Snon
148279697Snon#endif	/* SCSI_LOW_INTERFACE_CAM */
148379697Snon
148479697Snon/*=============================================================
148579697Snon * END OF OS switch  (All OS depend fucntions should be above)
148679697Snon =============================================================*/
148779697Snon
148879697Snon/**************************************************************
148979697Snon * scsi low deactivate and activate
149079697Snon **************************************************************/
149179697Snonint
149279697Snonscsi_low_is_busy(slp)
149379697Snon	struct scsi_low_softc *slp;
149479697Snon{
149579697Snon
149679697Snon	if (slp->sl_nio > 0)
149779697Snon		return EBUSY;
149879697Snon	return 0;
149979697Snon}
150079697Snon
150179697Snonint
150279697Snonscsi_low_deactivate(slp)
150379697Snon	struct scsi_low_softc *slp;
150479697Snon{
150579697Snon	int s;
150679697Snon
150779697Snon	s = SCSI_LOW_SPLSCSI();
150879697Snon	slp->sl_flags |= HW_INACTIVE;
150979697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
151079697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_STOP);
151179697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
151279697Snon		(slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP);
151379697Snon	splx(s);
151479697Snon	return 0;
151579697Snon}
151679697Snon
151779697Snonint
151879697Snonscsi_low_activate(slp)
151979697Snon	struct scsi_low_softc *slp;
152079697Snon{
152179697Snon	int error, s;
152279697Snon
152379697Snon	s = SCSI_LOW_SPLSCSI();
152479697Snon	slp->sl_flags &= ~HW_INACTIVE;
152579697Snon	if ((error = scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL)) != 0)
152679697Snon	{
152779697Snon		slp->sl_flags |= HW_INACTIVE;
152879697Snon		splx(s);
152979697Snon		return error;
153079697Snon	}
153179697Snon
153279697Snon	slp->sl_timeout_count = 0;
153379697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
153479697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
153579697Snon	splx(s);
153679697Snon	return 0;
153779697Snon}
153879697Snon
153979697Snon/**************************************************************
154079697Snon * scsi low log
154179697Snon **************************************************************/
154279697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
154392770Salfredstatic void scsi_low_msg_log_init(struct scsi_low_msg_log *);
154492770Salfredstatic void scsi_low_msg_log_write(struct scsi_low_msg_log *, u_int8_t *, int);
154592770Salfredstatic void scsi_low_msg_log_show(struct scsi_low_msg_log *, char *, int);
154679697Snon
154779697Snonstatic void
154879697Snonscsi_low_msg_log_init(slmlp)
154979697Snon	struct scsi_low_msg_log *slmlp;
155079697Snon{
155179697Snon
155279697Snon	slmlp->slml_ptr = 0;
155379697Snon}
155479697Snon
155579697Snonstatic void
155679697Snonscsi_low_msg_log_write(slmlp, datap, len)
155779697Snon	struct scsi_low_msg_log *slmlp;
155879697Snon	u_int8_t *datap;
155979697Snon	int len;
156079697Snon{
156179697Snon	int ptr, ind;
156279697Snon
156379697Snon	if (slmlp->slml_ptr >= SCSI_LOW_MSG_LOG_DATALEN)
156479697Snon		return;
156579697Snon
156679697Snon	ptr = slmlp->slml_ptr ++;
156779697Snon	for (ind = 0; ind < sizeof(slmlp->slml_msg[0]) && ind < len; ind ++)
156879697Snon		slmlp->slml_msg[ptr].msg[ind] = datap[ind];
156979697Snon	for ( ; ind < sizeof(slmlp->slml_msg[0]); ind ++)
157079697Snon		slmlp->slml_msg[ptr].msg[ind] = 0;
157179697Snon}
157279697Snon
157379697Snonstatic void
157479697Snonscsi_low_msg_log_show(slmlp, s, len)
157579697Snon	struct scsi_low_msg_log *slmlp;
157679697Snon	char *s;
157779697Snon	int len;
157879697Snon{
157979697Snon	int ptr, ind;
158079697Snon
158179697Snon	printf("%s: (%d) ", s, slmlp->slml_ptr);
158279697Snon	for (ptr = 0; ptr < slmlp->slml_ptr; ptr ++)
158379697Snon	{
158479697Snon		for (ind = 0; ind < len && ind < sizeof(slmlp->slml_msg[0]);
158579697Snon		     ind ++)
158679697Snon		{
158779697Snon			printf("[%x]", (u_int) slmlp->slml_msg[ptr].msg[ind]);
158879697Snon		}
158979697Snon		printf(">");
159079697Snon	}
159179697Snon	printf("\n");
159279697Snon}
159379697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
159479697Snon
159579697Snon/**************************************************************
159667468Snon * power control
159767468Snon **************************************************************/
159867468Snonstatic void
159967468Snonscsi_low_engage(arg)
160067468Snon	void *arg;
160167468Snon{
160267468Snon	struct scsi_low_softc *slp = arg;
160379697Snon	int s = SCSI_LOW_SPLSCSI();
160467468Snon
160567468Snon	switch (slp->sl_rstep)
160667468Snon	{
160767468Snon	case 0:
160867468Snon		slp->sl_rstep ++;
160967468Snon		(*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
161079697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp,
161179697Snon			SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_START);
161267468Snon		break;
161367468Snon
161467468Snon	case 1:
161567468Snon		slp->sl_rstep ++;
161667468Snon		slp->sl_flags &= ~HW_RESUME;
161767468Snon		scsi_low_start(slp);
161867468Snon		break;
161967468Snon
162067468Snon	case 2:
162167468Snon		break;
162267468Snon	}
162367468Snon	splx(s);
162467468Snon}
162567468Snon
162667468Snonstatic int
162767468Snonscsi_low_init(slp, flags)
162867468Snon	struct scsi_low_softc *slp;
162967468Snon	u_int flags;
163067468Snon{
163179697Snon	int rv = 0;
163267468Snon
163379697Snon	slp->sl_flags |= HW_INITIALIZING;
163479697Snon
163579697Snon	/* clear power control timeout */
163667468Snon	if ((slp->sl_flags & HW_POWERCTRL) != 0)
163767468Snon	{
163879697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp,
163979697Snon			SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP);
164067468Snon		slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME);
164167468Snon		slp->sl_active = 1;
164267468Snon		slp->sl_powc = SCSI_LOW_POWDOWN_TC;
164367468Snon	}
164467468Snon
164567468Snon	/* reset current nexus */
164667468Snon	scsi_low_reset_nexus(slp, flags);
164767468Snon	if ((slp->sl_flags & HW_INACTIVE) != 0)
164879697Snon	{
164979697Snon		rv = EBUSY;
165079697Snon		goto out;
165179697Snon	}
165267468Snon
165379697Snon	if (flags != SCSI_LOW_RESTART_SOFT)
165479697Snon	{
165579697Snon		rv = ((*slp->sl_funcs->scsi_low_init) (slp, flags));
165679697Snon	}
165767468Snon
165879697Snonout:
165979697Snon	slp->sl_flags &= ~HW_INITIALIZING;
166079697Snon	return rv;
166167468Snon}
166267468Snon
166367468Snon/**************************************************************
166467468Snon * allocate lun_info
166567468Snon **************************************************************/
166667468Snonstatic struct lun_info *
166767468Snonscsi_low_alloc_li(ti, lun, alloc)
166867468Snon	struct targ_info *ti;
166967468Snon	int lun;
167067468Snon	int alloc;
167167468Snon{
167279697Snon	struct scsi_low_softc *slp = ti->ti_sc;
167367468Snon	struct lun_info *li;
167467468Snon
167567468Snon	li = LIST_FIRST(&ti->ti_litab);
167667468Snon	if (li != NULL)
167767468Snon	{
167867468Snon		if (li->li_lun == lun)
167967468Snon			return li;
168067468Snon
168167468Snon		while ((li = LIST_NEXT(li, lun_chain)) != NULL)
168267468Snon		{
168367468Snon			if (li->li_lun == lun)
168467468Snon			{
168567468Snon				LIST_REMOVE(li, lun_chain);
168667468Snon				LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain);
168767468Snon				return li;
168867468Snon			}
168967468Snon		}
169067468Snon	}
169167468Snon
169267468Snon	if (alloc == 0)
169367468Snon		return li;
169467468Snon
169579697Snon	li = SCSI_LOW_MALLOC(ti->ti_lunsize);
169667468Snon	if (li == NULL)
1697106890Simp		panic("no lun info mem");
169867468Snon
169979697Snon	SCSI_LOW_BZERO(li, ti->ti_lunsize);
170067468Snon	li->li_lun = lun;
170167468Snon	li->li_ti = ti;
170267468Snon
170379697Snon	li->li_cfgflags = SCSI_LOW_SYNC | SCSI_LOW_LINK | SCSI_LOW_DISC |
170479697Snon			  SCSI_LOW_QTAG;
170579697Snon	li->li_quirks = li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
170679697Snon	li->li_flags_valid = SCSI_LOW_LUN_FLAGS_USER_VALID;
170779697Snon#ifdef	SCSI_LOW_FLAGS_QUIRKS_OK
170879697Snon	li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
170979697Snon#endif	/* SCSI_LOW_FLAGS_QUIRKS_OK */
171079697Snon
171179697Snon	li->li_qtagbits = (u_int) -1;
171279697Snon
171379697Snon	TAILQ_INIT(&li->li_discq);
171467468Snon	LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain);
171567468Snon
171679697Snon	/* host specific structure initialization per lun */
171779697Snon	if (slp->sl_funcs->scsi_low_lun_init != NULL)
171879697Snon		(*slp->sl_funcs->scsi_low_lun_init)
171979697Snon			(slp, ti, li, SCSI_LOW_INFO_ALLOC);
172079697Snon	scsi_low_calcf_lun(li);
172167468Snon	return li;
172267468Snon}
172367468Snon
172467468Snon/**************************************************************
172567468Snon * allocate targ_info
172667468Snon **************************************************************/
172767468Snonstatic struct targ_info *
172879697Snonscsi_low_alloc_ti(slp, targ)
172967468Snon	struct scsi_low_softc *slp;
173079697Snon	int targ;
173167468Snon{
173267468Snon	struct targ_info *ti;
173367468Snon
173471999Sphk	if (TAILQ_FIRST(&slp->sl_titab) == NULL)
173567468Snon		TAILQ_INIT(&slp->sl_titab);
173667468Snon
173779697Snon	ti = SCSI_LOW_MALLOC(slp->sl_targsize);
173867468Snon	if (ti == NULL)
1739106890Simp		panic("%s short of memory", slp->sl_xname);
174067468Snon
174179697Snon	SCSI_LOW_BZERO(ti, slp->sl_targsize);
174267468Snon	ti->ti_id = targ;
174367468Snon	ti->ti_sc = slp;
174467468Snon
174567468Snon	slp->sl_ti[targ] = ti;
174667468Snon	TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain);
174767468Snon	LIST_INIT(&ti->ti_litab);
174867468Snon
174979697Snon	ti->ti_quirks = ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
175079697Snon	ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
175179697Snon	ti->ti_flags_valid = SCSI_LOW_TARG_FLAGS_USER_VALID;
175279697Snon#ifdef	SCSI_LOW_FLAGS_QUIRKS_OK
175379697Snon	ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
175479697Snon#endif	/* SCSI_LOW_FLAGS_QUIRKS_OK */
175573025Snon
175679697Snon	if (slp->sl_funcs->scsi_low_targ_init != NULL)
175779697Snon	{
175879697Snon		(*slp->sl_funcs->scsi_low_targ_init)
175979697Snon			(slp, ti, SCSI_LOW_INFO_ALLOC);
176079697Snon	}
176179697Snon	scsi_low_calcf_target(ti);
176267468Snon	return ti;
176367468Snon}
176467468Snon
176567468Snonstatic void
176667468Snonscsi_low_free_ti(slp)
176767468Snon	struct scsi_low_softc *slp;
176867468Snon{
176967468Snon	struct targ_info *ti, *tib;
177067468Snon	struct lun_info *li, *nli;
177167468Snon
177271999Sphk	for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib)
177367468Snon	{
177467468Snon		for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli)
177567468Snon		{
177679697Snon			if (slp->sl_funcs->scsi_low_lun_init != NULL)
177779697Snon			{
177879697Snon				(*slp->sl_funcs->scsi_low_lun_init)
177979697Snon					(slp, ti, li, SCSI_LOW_INFO_DEALLOC);
178079697Snon			}
178167468Snon			nli = LIST_NEXT(li, lun_chain);
178279697Snon			SCSI_LOW_FREE(li);
178367468Snon		}
178479697Snon
178579697Snon		if (slp->sl_funcs->scsi_low_targ_init != NULL)
178679697Snon		{
178779697Snon			(*slp->sl_funcs->scsi_low_targ_init)
178879697Snon				(slp, ti, SCSI_LOW_INFO_DEALLOC);
178979697Snon		}
179079697Snon		tib = TAILQ_NEXT(ti, ti_chain);
179179697Snon		SCSI_LOW_FREE(ti);
179267468Snon	}
179367468Snon}
179467468Snon
179567468Snon/**************************************************************
179667468Snon * timeout
179767468Snon **************************************************************/
179867468Snonvoid
179979697Snonscsi_low_bus_idle(slp)
180079697Snon	struct scsi_low_softc *slp;
180179697Snon{
180279697Snon
180379697Snon	slp->sl_retry_sel = 0;
180479697Snon	if (slp->sl_Tnexus == NULL)
180579697Snon		scsi_low_start(slp);
180679697Snon}
180779697Snon
180879697Snonstatic void
180967468Snonscsi_low_timeout(arg)
181067468Snon	void *arg;
181167468Snon{
181267468Snon	struct scsi_low_softc *slp = arg;
181379697Snon	int s;
181479697Snon
181579697Snon	s = SCSI_LOW_SPLSCSI();
181679697Snon	(void) scsi_low_timeout_check(slp);
181779697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
181879697Snon		(slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
181979697Snon	splx(s);
182079697Snon}
182179697Snon
182279697Snonstatic int
182379697Snonscsi_low_timeout_check(slp)
182479697Snon	struct scsi_low_softc *slp;
182579697Snon{
182667468Snon	struct targ_info *ti;
182779697Snon	struct lun_info *li;
182867468Snon	struct slccb *cb = NULL;		/* XXX */
182967468Snon
183079697Snon	/* selection restart */
183179697Snon	if (slp->sl_retry_sel != 0)
183267468Snon	{
183379697Snon		slp->sl_retry_sel = 0;
183479697Snon		if (slp->sl_Tnexus != NULL)
183579697Snon			goto step1;
183667468Snon
183779697Snon		cb = TAILQ_FIRST(&slp->sl_start);
183879697Snon		if (cb == NULL)
183979697Snon			goto step1;
184079697Snon
184179697Snon		if (cb->ccb_selrcnt >= SCSI_LOW_MAX_SELECTION_RETRY)
184267468Snon		{
184379697Snon			cb->ccb_flags |= CCB_NORETRY;
184479697Snon			cb->ccb_error |= SELTIMEOUTIO;
184579697Snon			if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
1846106890Simp				panic("%s: ccb not finished", slp->sl_xname);
184767468Snon		}
184879697Snon
184979697Snon		if (slp->sl_Tnexus == NULL)
185079697Snon			scsi_low_start(slp);
185167468Snon	}
185279697Snon
185379697Snon	/* call hardware timeout */
185479697Snonstep1:
185579697Snon	if (slp->sl_funcs->scsi_low_timeout != NULL)
185667468Snon	{
185779697Snon		(*slp->sl_funcs->scsi_low_timeout) (slp);
185879697Snon	}
185979697Snon
186079697Snon	if (slp->sl_timeout_count ++ <
186179697Snon	    SCSI_LOW_TIMEOUT_CHECK_INTERVAL * SCSI_LOW_TIMEOUT_HZ)
186279697Snon		return 0;
186379697Snon
186479697Snon	slp->sl_timeout_count = 0;
186579697Snon	if (slp->sl_nio > 0)
186679697Snon	{
186779697Snon		if ((cb = slp->sl_Qnexus) != NULL)
186867468Snon		{
186967468Snon			cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
187067468Snon			if (cb->ccb_tc < 0)
187167468Snon				goto bus_reset;
187267468Snon		}
187379697Snon		else if (slp->sl_disc == 0)
187467468Snon		{
187579697Snon		        if ((cb = TAILQ_FIRST(&slp->sl_start)) == NULL)
187679697Snon				return 0;
187767468Snon
187879697Snon			cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
187979697Snon			if (cb->ccb_tc < 0)
188079697Snon				goto bus_reset;
188179697Snon		}
188279697Snon		else for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
188379697Snon		          ti = TAILQ_NEXT(ti, ti_chain))
188479697Snon		{
188579697Snon			if (ti->ti_disc == 0)
188679697Snon				continue;
188767468Snon
188879697Snon			for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
188979697Snon			     li = LIST_NEXT(li, lun_chain))
189067468Snon			{
189179697Snon				for (cb = TAILQ_FIRST(&li->li_discq);
189279697Snon				     cb != NULL;
189379697Snon				     cb = TAILQ_NEXT(cb, ccb_chain))
189479697Snon				{
189579697Snon					cb->ccb_tc -=
189679697Snon						SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
189779697Snon					if (cb->ccb_tc < 0)
189879697Snon						goto bus_reset;
189979697Snon				}
190067468Snon			}
190167468Snon		}
190279697Snon
190367468Snon	}
190479697Snon	else if ((slp->sl_flags & HW_POWERCTRL) != 0)
190579697Snon	{
190679697Snon		if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0)
190779697Snon			return 0;
190867468Snon
190979697Snon		if (slp->sl_active != 0)
191079697Snon		{
191179697Snon			slp->sl_powc = SCSI_LOW_POWDOWN_TC;
191279697Snon			slp->sl_active = 0;
191379697Snon			return 0;
191479697Snon		}
191567468Snon
191679697Snon		slp->sl_powc --;
191779697Snon		if (slp->sl_powc < 0)
191879697Snon		{
191979697Snon			slp->sl_powc = SCSI_LOW_POWDOWN_TC;
192079697Snon			slp->sl_flags |= HW_POWDOWN;
192179697Snon			(*slp->sl_funcs->scsi_low_power)
192279697Snon					(slp, SCSI_LOW_POWDOWN);
192379697Snon		}
192479697Snon	}
192579697Snon	return 0;
192667468Snon
192767468Snonbus_reset:
192867468Snon	cb->ccb_error |= TIMEOUTIO;
192979697Snon	printf("%s: slccb (0x%lx) timeout!\n", slp->sl_xname, (u_long) cb);
193067468Snon	scsi_low_info(slp, NULL, "scsi bus hangup. try to recover.");
193167468Snon	scsi_low_init(slp, SCSI_LOW_RESTART_HARD);
193267468Snon	scsi_low_start(slp);
193379697Snon	return ERESTART;
193467468Snon}
193567468Snon
193667468Snon
193779697Snonstatic int
193879697Snonscsi_low_abort_ccb(slp, cb)
193979697Snon	struct scsi_low_softc *slp;
194079697Snon	struct slccb *cb;
194179697Snon{
194279697Snon	struct targ_info *ti;
194379697Snon	struct lun_info *li;
194479697Snon	u_int msg;
194567468Snon
194679697Snon	if (cb == NULL)
194779697Snon		return EINVAL;
194879697Snon	if ((cb->ccb_omsgoutflag &
194979697Snon	     (SCSI_LOW_MSG_ABORT | SCSI_LOW_MSG_ABORT_QTAG)) != 0)
195079697Snon		return EBUSY;
195167468Snon
195279697Snon	ti = cb->ti;
195379697Snon	li = cb->li;
195479697Snon	if (cb->ccb_tag == SCSI_LOW_UNKTAG)
195579697Snon		msg = SCSI_LOW_MSG_ABORT;
195679697Snon	else
195779697Snon		msg = SCSI_LOW_MSG_ABORT_QTAG;
195867468Snon
195979697Snon	cb->ccb_error |= ABORTIO;
196079697Snon	cb->ccb_flags |= CCB_NORETRY;
196179697Snon	scsi_low_ccb_message_assert(cb, msg);
196267468Snon
196379697Snon	if (cb == slp->sl_Qnexus)
196479697Snon	{
196579697Snon		scsi_low_assert_msg(slp, ti, msg, 1);
196679697Snon	}
196779697Snon	else if ((cb->ccb_flags & CCB_DISCQ) != 0)
196879697Snon	{
196979697Snon		if (scsi_low_revoke_ccb(slp, cb, 0) == NULL)
1970106890Simp			panic("%s: revoked ccb done", slp->sl_xname);
197167468Snon
197279697Snon		cb->ccb_flags |= CCB_STARTQ;
197379697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
197467468Snon
197579697Snon		if (slp->sl_Tnexus == NULL)
197679697Snon			scsi_low_start(slp);
197779697Snon	}
197879697Snon	else
197979697Snon	{
198079697Snon		if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
1981106890Simp			panic("%s: revoked ccb retried", slp->sl_xname);
198279697Snon	}
198379697Snon	return 0;
198467468Snon}
198567468Snon
198679697Snon/**************************************************************
198779697Snon * Generic SCSI INTERFACE
198879697Snon **************************************************************/
198967468Snonint
199079697Snonscsi_low_attach(slp, openings, ntargs, nluns, targsize, lunsize)
199167468Snon	struct scsi_low_softc *slp;
199279697Snon	int openings, ntargs, nluns, targsize, lunsize;
199367468Snon{
199467468Snon	struct targ_info *ti;
199567468Snon	struct lun_info *li;
199679697Snon	int s, i, nccb, rv;
199767468Snon
199879697Snon#ifdef	SCSI_LOW_INTERFACE_XS
199979697Snon	slp->sl_osdep_fp = &scsi_low_osdep_funcs_xs;
200079697Snon#endif	/* SCSI_LOW_INTERFACE_XS */
200179697Snon#ifdef	SCSI_LOW_INTERFACE_CAM
200279697Snon	slp->sl_osdep_fp = &scsi_low_osdep_funcs_cam;
200379697Snon#endif	/* SCSI_LOW_INTERFACE_CAM */
200479697Snon
200579697Snon	if (slp->sl_osdep_fp == NULL)
2006106890Simp		panic("scsi_low: interface not spcified");
200779697Snon
200867468Snon	if (ntargs > SCSI_LOW_NTARGETS)
200967468Snon	{
201067468Snon		printf("scsi_low: %d targets are too large\n", ntargs);
201167468Snon		printf("change kernel options SCSI_LOW_NTARGETS");
201279697Snon		return EINVAL;
201367468Snon	}
201467468Snon
201579697Snon	if (openings <= 0)
201679697Snon		slp->sl_openings = (SCSI_LOW_NCCB / ntargs);
201779697Snon	else
201879697Snon		slp->sl_openings = openings;
201979697Snon	slp->sl_ntargs = ntargs;
202079697Snon	slp->sl_nluns = nluns;
202179697Snon	slp->sl_max_retry = SCSI_LOW_MAX_RETRY;
202267468Snon
202379697Snon	if (lunsize < sizeof(struct lun_info))
202479697Snon		lunsize = sizeof(struct lun_info);
202579697Snon
202679697Snon	if (targsize < sizeof(struct targ_info))
202779697Snon		targsize = sizeof(struct targ_info);
202879697Snon
202979697Snon	slp->sl_targsize = targsize;
203067468Snon	for (i = 0; i < ntargs; i ++)
203167468Snon	{
203279697Snon		ti = scsi_low_alloc_ti(slp, i);
203379697Snon		ti->ti_lunsize = lunsize;
203467468Snon		li = scsi_low_alloc_li(ti, 0, 1);
203567468Snon	}
203667468Snon
203767468Snon	/* initialize queue */
203879697Snon	nccb = openings * ntargs;
203967468Snon	if (nccb >= SCSI_LOW_NCCB || nccb <= 0)
204067468Snon		nccb = SCSI_LOW_NCCB;
204167468Snon	scsi_low_init_ccbque(nccb);
204267468Snon	TAILQ_INIT(&slp->sl_start);
204367468Snon
204479697Snon	/* call os depend attach */
204579697Snon	s = SCSI_LOW_SPLSCSI();
204679697Snon	rv = (*slp->sl_osdep_fp->scsi_low_osdep_attach) (slp);
204779697Snon	if (rv != 0)
204879697Snon	{
204979697Snon		splx(s);
205079697Snon		printf("%s: scsi_low_attach: osdep attach failed\n",
205179697Snon			slp->sl_xname);
205279697Snon		return EINVAL;
205379697Snon	}
205467468Snon
205579697Snon	/* check hardware */
205679697Snon	SCSI_LOW_DELAY(1000);	/* wait for 1ms */
205779697Snon	if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0)
205879697Snon	{
205979697Snon		splx(s);
206079697Snon		printf("%s: scsi_low_attach: initialization failed\n",
206179697Snon			slp->sl_xname);
206279697Snon		return EINVAL;
206379697Snon	}
206467468Snon
206567468Snon	/* start watch dog */
206679697Snon	slp->sl_timeout_count = 0;
206779697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
206879697Snon		 (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
206979697Snon	LIST_INSERT_HEAD(&sl_tab, slp, sl_chain);
207067468Snon
207179697Snon	/* fake call */
207279697Snon	scsi_low_abort_ccb(slp, scsi_low_find_ccb(slp, 0, 0, NULL));
207367468Snon
207479697Snon#ifdef	SCSI_LOW_START_UP_CHECK
207579697Snon	/* probing devices */
207679697Snon	scsi_low_start_up(slp);
207779697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
207867468Snon
207979697Snon	/* call os depend attach done*/
208079697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_world_start) (slp);
208179697Snon	splx(s);
208279697Snon	return 0;
208367468Snon}
208467468Snon
208567468Snonint
208667468Snonscsi_low_dettach(slp)
208767468Snon	struct scsi_low_softc *slp;
208867468Snon{
208979697Snon	int s, rv;
209067468Snon
209179697Snon	s = SCSI_LOW_SPLSCSI();
209279697Snon	if (scsi_low_is_busy(slp) != 0)
209379697Snon	{
209479697Snon		splx(s);
209567468Snon		return EBUSY;
209679697Snon	}
209767468Snon
209879697Snon	scsi_low_deactivate(slp);
209967468Snon
210079697Snon	rv = (*slp->sl_osdep_fp->scsi_low_osdep_dettach) (slp);
210179697Snon	if (rv != 0)
210279697Snon	{
210379697Snon		splx(s);
210479697Snon		return EBUSY;
210579697Snon	}
210667468Snon
210767468Snon	scsi_low_free_ti(slp);
210879697Snon	LIST_REMOVE(slp, sl_chain);
210979697Snon	splx(s);
211067468Snon	return 0;
211167468Snon}
211267468Snon
211379697Snon/**************************************************************
211479697Snon * Generic enqueue
211579697Snon **************************************************************/
211679697Snonstatic int
211779697Snonscsi_low_enqueue(slp, ti, li, cb, flags, msg)
211879697Snon	struct scsi_low_softc *slp;
211967468Snon	struct targ_info *ti;
212067468Snon	struct lun_info *li;
212167468Snon	struct slccb *cb;
212279697Snon	u_int flags, msg;
212379697Snon{
212467468Snon
212579697Snon	cb->ti = ti;
212679697Snon	cb->li = li;
212767468Snon
212879697Snon	scsi_low_ccb_message_assert(cb, msg);
212967468Snon
213079697Snon	cb->ccb_otag = cb->ccb_tag = SCSI_LOW_UNKTAG;
213179697Snon	scsi_low_alloc_qtag(cb);
213267468Snon
213379697Snon	cb->ccb_flags = flags | CCB_STARTQ;
213479697Snon	cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
213579697Snon	cb->ccb_error |= PENDINGIO;
213679697Snon
213779697Snon	if ((flags & CCB_URGENT) != 0)
213879697Snon	{
213979697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
214079697Snon	}
214179697Snon	else
214279697Snon	{
214367468Snon		TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain);
214479697Snon	}
214567468Snon
214679697Snon	slp->sl_nio ++;
214767468Snon
214879697Snon	if (slp->sl_Tnexus == NULL)
214979697Snon		scsi_low_start(slp);
215079697Snon	return 0;
215179697Snon}
215267468Snon
215379697Snonstatic int
215479697Snonscsi_low_message_enqueue(slp, ti, li, flags)
215579697Snon	struct scsi_low_softc *slp;
215679697Snon	struct targ_info *ti;
215779697Snon	struct lun_info *li;
215879697Snon	u_int flags;
215979697Snon{
216079697Snon	struct slccb *cb;
216179697Snon	u_int tmsgflags;
216267468Snon
216379697Snon	tmsgflags = ti->ti_setup_msg;
216479697Snon	ti->ti_setup_msg = 0;
216567468Snon
216679697Snon	flags |= CCB_NORETRY;
216779697Snon	if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
216879697Snon		return ENOMEM;
216967468Snon
217079697Snon	cb->osdep = NULL;
217179697Snon	cb->bp = NULL;
217279697Snon	scsi_low_enqueue(slp, ti, li, cb, flags, tmsgflags);
217379697Snon	return 0;
217479697Snon}
217567468Snon
217679697Snon/**************************************************************
217779697Snon * Generic Start & Done
217879697Snon **************************************************************/
217979697Snon#define	SLSC_MODE_SENSE_SHORT   0x1a
218079697Snonstatic u_int8_t ss_cmd[6] = {START_STOP, 0, 0, 0, SSS_START, 0};
218179697Snonstatic u_int8_t sms_cmd[6] = {SLSC_MODE_SENSE_SHORT, 0x08, 0x0a, 0,
218279697Snon			      sizeof(struct scsi_low_mode_sense_data), 0};
218379697Snonstatic u_int8_t inq_cmd[6] = {INQUIRY, 0, 0, 0,
218479697Snon			      sizeof(struct scsi_low_inq_data), 0};
218579697Snonstatic u_int8_t unit_ready_cmd[6];
218692770Salfredstatic int scsi_low_setup_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *);
218792770Salfredstatic int scsi_low_sense_abort_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *);
218892770Salfredstatic int scsi_low_resume(struct scsi_low_softc *);
218979697Snon
219079697Snonstatic void
219179697Snonscsi_low_unit_ready_cmd(cb)
219279697Snon	struct slccb *cb;
219379697Snon{
219479697Snon
219579697Snon	cb->ccb_scp.scp_cmd = unit_ready_cmd;
219679697Snon	cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd);
219779697Snon	cb->ccb_scp.scp_datalen = 0;
219879697Snon	cb->ccb_scp.scp_direction = SCSI_LOW_READ;
219979697Snon	cb->ccb_tcmax = 15;
220067468Snon}
220179697Snon
220267468Snonstatic int
220379697Snonscsi_low_sense_abort_start(slp, ti, li, cb)
220479697Snon	struct scsi_low_softc *slp;
220567468Snon	struct targ_info *ti;
220679697Snon	struct lun_info *li;
220767468Snon	struct slccb *cb;
220879697Snon{
220967468Snon
221079697Snon	cb->ccb_scp.scp_cmdlen = 6;
221179697Snon	SCSI_LOW_BZERO(cb->ccb_scsi_cmd, cb->ccb_scp.scp_cmdlen);
221279697Snon	cb->ccb_scsi_cmd[0] = REQUEST_SENSE;
221379697Snon	cb->ccb_scsi_cmd[4] = sizeof(cb->ccb_sense);
221479697Snon	cb->ccb_scp.scp_cmd = cb->ccb_scsi_cmd;
221579697Snon	cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense;
221679697Snon	cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense);
221779697Snon	cb->ccb_scp.scp_direction = SCSI_LOW_READ;
221879697Snon	cb->ccb_tcmax = 15;
221979697Snon	scsi_low_ccb_message_clear(cb);
222079697Snon	if ((cb->ccb_flags & CCB_CLEARQ) != 0)
222167468Snon	{
222279697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
222367468Snon	}
222479697Snon	else
222579697Snon	{
222679697Snon		SCSI_LOW_BZERO(&cb->ccb_sense, sizeof(cb->ccb_sense));
222779697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
222879697Snon		scsi_low_assert_msg(slp, ti, ti->ti_setup_msg_done, 0);
222979697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
223079697Snon	}
223167468Snon
223279697Snon	return SCSI_LOW_START_NO_QTAG;
223379697Snon}
223467468Snon
223579697Snonstatic int
223679697Snonscsi_low_setup_start(slp, ti, li, cb)
223779697Snon	struct scsi_low_softc *slp;
223879697Snon	struct targ_info *ti;
223979697Snon	struct lun_info *li;
224079697Snon	struct slccb *cb;
224179697Snon{
224267468Snon
224379697Snon	switch(li->li_state)
224479697Snon	{
224579697Snon	case SCSI_LOW_LUN_SLEEP:
224679697Snon		scsi_low_unit_ready_cmd(cb);
224779697Snon		break;
224867468Snon
224979697Snon	case SCSI_LOW_LUN_START:
225079697Snon		cb->ccb_scp.scp_cmd = ss_cmd;
225179697Snon		cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd);
225279697Snon		cb->ccb_scp.scp_datalen = 0;
225379697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
225479697Snon		cb->ccb_tcmax = 30;
225579697Snon		break;
225667468Snon
225779697Snon	case SCSI_LOW_LUN_INQ:
225879697Snon		cb->ccb_scp.scp_cmd = inq_cmd;
225979697Snon		cb->ccb_scp.scp_cmdlen = sizeof(inq_cmd);
226079697Snon		cb->ccb_scp.scp_data = (u_int8_t *)&li->li_inq;
226179697Snon		cb->ccb_scp.scp_datalen = sizeof(li->li_inq);
226279697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
226379697Snon		cb->ccb_tcmax = 15;
226479697Snon		break;
226567468Snon
226679697Snon	case SCSI_LOW_LUN_MODEQ:
226779697Snon		cb->ccb_scp.scp_cmd = sms_cmd;
226879697Snon		cb->ccb_scp.scp_cmdlen = sizeof(sms_cmd);
226979697Snon		cb->ccb_scp.scp_data = (u_int8_t *)&li->li_sms;
227079697Snon		cb->ccb_scp.scp_datalen = sizeof(li->li_sms);
227179697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
227279697Snon		cb->ccb_tcmax = 15;
227379697Snon		return SCSI_LOW_START_QTAG;
227467468Snon
227579697Snon	default:
2276106890Simp		panic("%s: no setup phase", slp->sl_xname);
227767468Snon	}
227867468Snon
227979697Snon	return SCSI_LOW_START_NO_QTAG;
228067468Snon}
228167468Snon
228279697Snonstatic int
228379697Snonscsi_low_resume(slp)
228479697Snon	struct scsi_low_softc *slp;
228567468Snon{
228667468Snon
228779697Snon	if (slp->sl_flags & HW_RESUME)
228879697Snon		return EJUSTRETURN;
228979697Snon	slp->sl_flags &= ~HW_POWDOWN;
229079697Snon	if (slp->sl_funcs->scsi_low_power != NULL)
229179697Snon	{
229279697Snon		slp->sl_flags |= HW_RESUME;
229379697Snon		slp->sl_rstep = 0;
229479697Snon		(*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
229579697Snon		(*slp->sl_osdep_fp->scsi_low_osdep_timeout)
229679697Snon					(slp, SCSI_LOW_TIMEOUT_CH_ENGAGE,
229779697Snon				         SCSI_LOW_TIMEOUT_START);
229879697Snon		return EJUSTRETURN;
229979697Snon	}
230079697Snon	return 0;
230167468Snon}
230267468Snon
230367468Snonstatic void
230467468Snonscsi_low_start(slp)
230567468Snon	struct scsi_low_softc *slp;
230667468Snon{
230767468Snon	struct targ_info *ti;
230867468Snon	struct lun_info *li;
230967468Snon	struct slccb *cb;
231067468Snon	int rv;
231167468Snon
231279697Snon	/* check hardware exists or under initializations ? */
231379697Snon	if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0)
231467468Snon		return;
231567468Snon
231667468Snon	/* check hardware power up ? */
231767468Snon	if ((slp->sl_flags & HW_POWERCTRL) != 0)
231867468Snon	{
231967468Snon		slp->sl_active ++;
232067468Snon		if (slp->sl_flags & (HW_POWDOWN | HW_RESUME))
232167468Snon		{
232279697Snon			if (scsi_low_resume(slp) == EJUSTRETURN)
232367468Snon				return;
232467468Snon		}
232567468Snon	}
232667468Snon
232767468Snon	/* setup nexus */
232867468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
232979697Snon	if (slp->sl_Tnexus || slp->sl_Lnexus || slp->sl_Qnexus)
233067468Snon	{
233167468Snon		scsi_low_info(slp, NULL, "NEXUS INCOSISTENT");
2332106890Simp		panic("%s: inconsistent", slp->sl_xname);
233367468Snon	}
233467468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
233567468Snon
233679697Snon	for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL;
233779697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
233867468Snon	{
233967468Snon		li = cb->li;
234079697Snon
234179697Snon		if (li->li_disc == 0)
234279697Snon		{
234367468Snon			goto scsi_low_cmd_start;
234479697Snon		}
234579697Snon		else if (li->li_nqio > 0)
234679697Snon		{
234779697Snon			if (li->li_nqio < li->li_maxnqio ||
234879697Snon		            (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
234979697Snon				goto scsi_low_cmd_start;
235079697Snon		}
235167468Snon	}
235267468Snon	return;
235367468Snon
235467468Snonscsi_low_cmd_start:
235579697Snon	cb->ccb_flags &= ~CCB_STARTQ;
235679697Snon	TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
235779697Snon	ti = cb->ti;
235867468Snon
235967468Snon	/* clear all error flag bits (for restart) */
236067468Snon	cb->ccb_error = 0;
236179697Snon	cb->ccb_datalen = -1;
236279697Snon	cb->ccb_scp.scp_status = ST_UNKNOWN;
236367468Snon
236467468Snon	/* setup nexus pointer */
236579697Snon	slp->sl_Qnexus = cb;
236679697Snon	slp->sl_Lnexus = li;
236779697Snon	slp->sl_Tnexus = ti;
236867468Snon
236967468Snon	/* initialize msgsys */
237067468Snon	scsi_low_init_msgsys(slp, ti);
237167468Snon
237279697Snon	/* exec cmd */
237379697Snon	if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
237467468Snon	{
237579697Snon		/* CA state or forced abort */
237679697Snon		rv = scsi_low_sense_abort_start(slp, ti, li, cb);
237767468Snon	}
237879697Snon	else if (li->li_state >= SCSI_LOW_LUN_OK)
237967468Snon	{
238079697Snon		cb->ccb_flags &= ~CCB_INTERNAL;
238179697Snon		rv = (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, cb);
238279697Snon		if (cb->ccb_msgoutflag != 0)
238379697Snon		{
238479697Snon			scsi_low_ccb_message_exec(slp, cb);
238579697Snon		}
238667468Snon	}
238779697Snon	else
238867468Snon	{
238979697Snon		cb->ccb_flags |= CCB_INTERNAL;
239079697Snon		rv = scsi_low_setup_start(slp, ti, li, cb);
239179697Snon	}
239267468Snon
239379697Snon	/* allocate qtag */
239479697Snon#define	SCSI_LOW_QTAG_OK (SCSI_LOW_QTAG | SCSI_LOW_DISC)
239567468Snon
239679697Snon	if (rv == SCSI_LOW_START_QTAG &&
239779697Snon	    (li->li_flags & SCSI_LOW_QTAG_OK) == SCSI_LOW_QTAG_OK &&
239879697Snon	    li->li_maxnqio > 0)
239979697Snon	{
240079697Snon		u_int qmsg;
240167468Snon
240279697Snon		scsi_low_activate_qtag(cb);
240379697Snon		if ((scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
240479697Snon		     SCSI_LOW_CMD_ORDERED_QTAG) != 0)
240579697Snon			qmsg = SCSI_LOW_MSG_ORDERED_QTAG;
240679697Snon		else if ((cb->ccb_flags & CCB_URGENT) != 0)
240779697Snon			qmsg = SCSI_LOW_MSG_HEAD_QTAG;
240879697Snon		else
240979697Snon			qmsg = SCSI_LOW_MSG_SIMPLE_QTAG;
241079697Snon		scsi_low_assert_msg(slp, ti, qmsg, 0);
241167468Snon	}
241267468Snon
241367468Snon	/* timeout */
241467468Snon	if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT)
241567468Snon		cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
241667468Snon	cb->ccb_tc = cb->ccb_tcmax;
241767468Snon
241867468Snon	/* setup saved scsi data pointer */
241967468Snon	cb->ccb_sscp = cb->ccb_scp;
242067468Snon
242167468Snon	/* setup current scsi pointer */
242267468Snon	slp->sl_scp = cb->ccb_sscp;
242367468Snon	slp->sl_error = cb->ccb_error;
242467468Snon
242579697Snon	/* assert always an identify msg */
242679697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
242779697Snon
242879697Snon	/* debug section */
242979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
243079697Snon	scsi_low_msg_log_init(&ti->ti_log_msgin);
243179697Snon	scsi_low_msg_log_init(&ti->ti_log_msgout);
243279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
243379697Snon
243467468Snon	/* selection start */
243579697Snon	slp->sl_selid = cb;
243667468Snon	rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb));
243767468Snon	if (rv == SCSI_LOW_START_OK)
243867468Snon	{
243967468Snon#ifdef	SCSI_LOW_STATICS
244067468Snon		scsi_low_statics.nexus_win ++;
244167468Snon#endif	/* SCSI_LOW_STATICS */
244267468Snon		return;
244367468Snon	}
244467468Snon
244579697Snon	scsi_low_arbit_fail(slp, cb);
244667468Snon#ifdef	SCSI_LOW_STATICS
244767468Snon	scsi_low_statics.nexus_fail ++;
244867468Snon#endif	/* SCSI_LOW_STATICS */
244967468Snon}
245067468Snon
245167468Snonvoid
245279697Snonscsi_low_arbit_fail(slp, cb)
245367468Snon	struct scsi_low_softc *slp;
245479697Snon	struct slccb *cb;
245579697Snon{
245679697Snon	struct targ_info *ti = cb->ti;
245779697Snon
245879697Snon	scsi_low_deactivate_qtag(cb);
245979697Snon	scsi_low_ccb_message_retry(cb);
246079697Snon	cb->ccb_flags |= CCB_STARTQ;
246179697Snon	TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
246279697Snon
246379697Snon	scsi_low_bus_release(slp, ti);
246479697Snon
246579697Snon	cb->ccb_selrcnt ++;
246679697Snon	if (slp->sl_disc == 0)
246779697Snon	{
246879697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
246979697Snon		printf("%s: try selection again\n", slp->sl_xname);
247079697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
247179697Snon		slp->sl_retry_sel = 1;
247279697Snon	}
247379697Snon}
247479697Snon
247579697Snonstatic void
247679697Snonscsi_low_bus_release(slp, ti)
247779697Snon	struct scsi_low_softc *slp;
247867468Snon	struct targ_info *ti;
247967468Snon{
248067468Snon
248179697Snon	if (ti->ti_disc > 0)
248279697Snon	{
248379697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DISC);
248479697Snon	}
248579697Snon	else
248679697Snon	{
248779697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
248879697Snon	}
248979697Snon
249067468Snon	/* clear all nexus pointer */
249179697Snon	slp->sl_Qnexus = NULL;
249279697Snon	slp->sl_Lnexus = NULL;
249379697Snon	slp->sl_Tnexus = NULL;
249467468Snon
249567468Snon	/* clear selection assert */
249667468Snon	slp->sl_selid = NULL;
249767468Snon
249867468Snon	/* clear nexus data */
249967468Snon	slp->sl_scp.scp_direction = SCSI_LOW_RWUNK;
250079697Snon
250179697Snon	/* clear phase change counter */
250279697Snon	slp->sl_ph_count = 0;
250367468Snon}
250467468Snon
250567468Snonstatic int
250679697Snonscsi_low_setup_done(slp, cb)
250767468Snon	struct scsi_low_softc *slp;
250867468Snon	struct slccb *cb;
250967468Snon{
251067468Snon	struct targ_info *ti;
251167468Snon	struct lun_info *li;
251267468Snon
251367468Snon	ti = cb->ti;
251467468Snon	li = cb->li;
251579697Snon
251679697Snon	if (cb->ccb_rcnt >= slp->sl_max_retry)
251767468Snon	{
251879697Snon		cb->ccb_error |= ABORTIO;
251979697Snon		return SCSI_LOW_DONE_COMPLETE;
252079697Snon	}
252179697Snon
252279697Snon	/* XXX: special huck for selection timeout */
252379697Snon	if (li->li_state == SCSI_LOW_LUN_SLEEP &&
252479697Snon	    (cb->ccb_error & SELTIMEOUTIO) != 0)
252579697Snon	{
252679697Snon		cb->ccb_error |= ABORTIO;
252779697Snon		return SCSI_LOW_DONE_COMPLETE;
252879697Snon	}
252979697Snon
253079697Snon	switch(li->li_state)
253179697Snon	{
253279697Snon	case SCSI_LOW_LUN_INQ:
253379697Snon		if (cb->ccb_error != 0)
253467468Snon		{
253579697Snon			li->li_diskflags &=
253679697Snon				~(SCSI_LOW_DISK_LINK | SCSI_LOW_DISK_QTAG);
253779697Snon			if (li->li_lun > 0)
253879697Snon				goto resume;
253979697Snon			ti->ti_diskflags &=
254079697Snon				~(SCSI_LOW_DISK_SYNC | SCSI_LOW_DISK_WIDE);
254167468Snon		}
254279697Snon		else if ((li->li_inq.sd_version & 7) >= 2 ||
254379697Snon		         (li->li_inq.sd_len >= 4))
254467468Snon		{
254579697Snon			if ((li->li_inq.sd_support & 0x2) == 0)
254679697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
254779697Snon			if ((li->li_inq.sd_support & 0x8) == 0)
254879697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_LINK;
254979697Snon			if (li->li_lun > 0)
255079697Snon				goto resume;
255179697Snon			if ((li->li_inq.sd_support & 0x10) == 0)
255279697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_SYNC;
255379697Snon			if ((li->li_inq.sd_support & 0x20) == 0)
255479697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_16;
255579697Snon			if ((li->li_inq.sd_support & 0x40) == 0)
255679697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_32;
255779697Snon		}
255879697Snon		else
255979697Snon		{
256079697Snon			li->li_diskflags &=
256179697Snon				~(SCSI_LOW_DISK_QTAG | SCSI_LOW_DISK_LINK);
256279697Snon			if (li->li_lun > 0)
256379697Snon				goto resume;
256479697Snon			ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE;
256579697Snon		}
256679697Snon		ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_DISK_VALID;
256779697Snonresume:
256879697Snon		scsi_low_calcf_target(ti);
256979697Snon		scsi_low_calcf_lun(li);
257079697Snon		break;
257179697Snon
257279697Snon	case SCSI_LOW_LUN_MODEQ:
257379697Snon		if (cb->ccb_error != 0)
257479697Snon		{
257579697Snon			if (cb->ccb_error & SENSEIO)
257667468Snon			{
257779697Snon#ifdef	SCSI_LOW_DEBUG
257879697Snon				if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE)
257979697Snon				{
2580226067Sken					int error_code, sense_key, asc, ascq;
2581226067Sken
2582226067Sken					scsi_extract_sense(&cb->ccb_sense,
2583226067Sken							   &error_code,
2584226067Sken							   &sense_key,
2585226067Sken							   &asc,
2586226067Sken							   &ascq);
2587226067Sken					printf("SENSE: [%x][%x][%x][%x]\n",
2588226067Sken					       error_code, sense_key, asc,
2589226067Sken					       ascq);
259079697Snon				}
259179697Snon#endif	/* SCSI_LOW_DEBUG */
259267468Snon			}
259379697Snon			else
259479697Snon			{
259579697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
259679697Snon			}
259779697Snon		}
259879697Snon		else if ((li->li_sms.sms_cmp.cmp_page & 0x3f) == 0x0a)
259979697Snon		{
260079697Snon			if (li->li_sms.sms_cmp.cmp_qc & 0x02)
260179697Snon				li->li_qflags |= SCSI_LOW_QFLAG_CA_QCLEAR;
260279697Snon			else
260379697Snon				li->li_qflags &= ~SCSI_LOW_QFLAG_CA_QCLEAR;
260479697Snon			if ((li->li_sms.sms_cmp.cmp_qc & 0x01) != 0)
260579697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
260679697Snon		}
260779697Snon		li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_DISK_VALID;
260879697Snon		scsi_low_calcf_lun(li);
260979697Snon		break;
261067468Snon
261179697Snon	default:
261279697Snon		break;
261379697Snon	}
261479697Snon
261579697Snon	li->li_state ++;
261679697Snon	if (li->li_state == SCSI_LOW_LUN_OK)
261779697Snon	{
261879697Snon		scsi_low_calcf_target(ti);
261979697Snon		scsi_low_calcf_lun(li);
262079697Snon		if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID &&
262179697Snon	            (slp->sl_show_result & SHOW_CALCF_RES) != 0)
262279697Snon		{
262379697Snon			scsi_low_calcf_show(li);
262479697Snon		}
262579697Snon	}
262679697Snon
262779697Snon	cb->ccb_rcnt --;
262879697Snon	return SCSI_LOW_DONE_RETRY;
262979697Snon}
263079697Snon
263179697Snonstatic int
263279697Snonscsi_low_done(slp, cb)
263379697Snon	struct scsi_low_softc *slp;
263479697Snon	struct slccb *cb;
263579697Snon{
263679697Snon	int rv;
263779697Snon
263879697Snon	if (cb->ccb_error == 0)
263979697Snon	{
264079697Snon		if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
264179697Snon		{
264279697Snon#ifdef	SCSI_LOW_QCLEAR_AFTER_CA
264379697Snon			/* XXX:
264479697Snon			 * SCSI-2 draft suggests
264579697Snon			 * page 0x0a QErr bit determins if
264679697Snon			 * the target aborts or continues
264779697Snon			 * the queueing io's after CA state resolved.
264879697Snon			 * However many targets seem not to support
264979697Snon			 * the page 0x0a. Thus we should manually clear the
265079697Snon			 * queuing io's after CA state.
265179697Snon			 */
265279697Snon			if ((cb->ccb_flags & CCB_CLEARQ) == 0)
265367468Snon			{
265479697Snon				cb->ccb_rcnt --;
265579697Snon				cb->ccb_flags |= CCB_CLEARQ;
265679697Snon				goto retry;
265779697Snon			}
265879697Snon#endif	/* SCSI_LOW_QCLEAR_AFTER_CA */
265979697Snon
266079697Snon			if ((cb->ccb_flags & CCB_SENSE) != 0)
266179697Snon				cb->ccb_error |= (SENSEIO | ABORTIO);
266279697Snon			cb->ccb_flags &= ~(CCB_SENSE | CCB_CLEARQ);
266379697Snon		}
266479697Snon		else switch (cb->ccb_sscp.scp_status)
266579697Snon		{
266679697Snon		case ST_GOOD:
266779697Snon		case ST_MET:
266879697Snon		case ST_INTERGOOD:
266979697Snon		case ST_INTERMET:
267079697Snon			if (cb->ccb_datalen == 0 ||
267179697Snon			    cb->ccb_scp.scp_datalen == 0)
267267468Snon				break;
267367468Snon
267479697Snon			if (cb->ccb_scp.scp_cmdlen > 0 &&
267579697Snon			    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
267679697Snon			     SCSI_LOW_CMD_RESIDUAL_CHK) == 0)
267779697Snon				break;
267879697Snon
267967468Snon			cb->ccb_error |= PDMAERR;
268067468Snon			break;
268167468Snon
268279697Snon		case ST_BUSY:
268379697Snon		case ST_QUEFULL:
268479697Snon			cb->ccb_error |= (BUSYERR | STATERR);
268579697Snon			break;
268679697Snon
268779697Snon		case ST_CONFLICT:
268879697Snon			cb->ccb_error |= (STATERR | ABORTIO);
268979697Snon			break;
269079697Snon
269167468Snon		case ST_CHKCOND:
269279697Snon		case ST_CMDTERM:
269379697Snon			if (cb->ccb_flags & (CCB_AUTOSENSE | CCB_INTERNAL))
269479697Snon			{
269579697Snon				cb->ccb_rcnt --;
269673025Snon				cb->ccb_flags |= CCB_SENSE;
269773025Snon				goto retry;
269873025Snon			}
269979697Snon			cb->ccb_error |= (UACAERR | STATERR | ABORTIO);
270073025Snon			break;
270167468Snon
270279697Snon		case ST_UNKNOWN:
270367468Snon		default:
270467468Snon			cb->ccb_error |= FATALIO;
270567468Snon			break;
270667468Snon		}
270767468Snon	}
270867468Snon	else
270967468Snon	{
271079697Snon		if (cb->ccb_flags & CCB_SENSE)
271167468Snon		{
271279697Snon			cb->ccb_error |= (SENSEERR | ABORTIO);
271367468Snon		}
271479697Snon		cb->ccb_flags &= ~(CCB_CLEARQ | CCB_SENSE);
271579697Snon	}
271667468Snon
271779697Snon	/* internal ccb */
271879697Snon	if ((cb->ccb_flags & CCB_INTERNAL) != 0)
271979697Snon	{
272079697Snon		if (scsi_low_setup_done(slp, cb) == SCSI_LOW_DONE_RETRY)
272179697Snon			goto retry;
272267468Snon	}
272367468Snon
272479697Snon	/* check a ccb msgout flag */
272579697Snon	if (cb->ccb_omsgoutflag != 0)
272667468Snon	{
272779697Snon#define	SCSI_LOW_MSG_ABORT_OK	(SCSI_LOW_MSG_ABORT | \
272879697Snon				 SCSI_LOW_MSG_ABORT_QTAG | \
272979697Snon				 SCSI_LOW_MSG_CLEAR_QTAG | \
273079697Snon				 SCSI_LOW_MSG_TERMIO)
273179697Snon
273279697Snon		if ((cb->ccb_omsgoutflag & SCSI_LOW_MSG_ABORT_OK) != 0)
273367468Snon		{
273479697Snon			cb->ccb_error |= ABORTIO;
273567468Snon		}
273667468Snon	}
273767468Snon
273879697Snon	/* call OS depend done */
273979697Snon	if (cb->osdep != NULL)
274067468Snon	{
274179697Snon		rv = (*slp->sl_osdep_fp->scsi_low_osdep_done) (slp, cb);
274279697Snon		if (rv == EJUSTRETURN)
274379697Snon			goto retry;
274467468Snon	}
274579697Snon	else if (cb->ccb_error != 0)
274667468Snon	{
274779697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
274879697Snon			cb->ccb_error |= ABORTIO;
274979697Snon
275079697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
275179697Snon		    (cb->ccb_error & ABORTIO) == 0)
275267468Snon			goto retry;
275367468Snon	}
275479697Snon
275579697Snon	/* free our target */
275679697Snon#ifdef	SCSI_LOW_DEBUG
275779697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
275867468Snon	{
275979697Snon		printf(">> SCSI_LOW_DONE_COMPLETE ===============\n");
276079697Snon		scsi_low_print(slp, NULL);
276167468Snon	}
276279697Snon#endif	/* SCSI_LOW_DEBUG */
276367468Snon
276479697Snon	scsi_low_deactivate_qtag(cb);
276579697Snon	scsi_low_dealloc_qtag(cb);
276667468Snon	scsi_low_free_ccb(cb);
276779697Snon	slp->sl_nio --;
276867468Snon	return SCSI_LOW_DONE_COMPLETE;
276967468Snon
277067468Snonretry:
277179697Snon#ifdef	SCSI_LOW_DEBUG
277279697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
277367468Snon	{
277479697Snon		printf("** SCSI_LOW_DONE_RETRY ===============\n");
277579697Snon		scsi_low_print(slp, NULL);
277667468Snon	}
277779697Snon#endif	/* SCSI_LOW_DEBUG */
277879697Snon
277979697Snon	cb->ccb_rcnt ++;
278079697Snon	scsi_low_deactivate_qtag(cb);
278179697Snon	scsi_low_ccb_message_retry(cb);
278267468Snon	return SCSI_LOW_DONE_RETRY;
278367468Snon}
278467468Snon
278567468Snon/**************************************************************
278667468Snon * Reset
278767468Snon **************************************************************/
278867468Snonstatic void
278979697Snonscsi_low_reset_nexus_target(slp, ti, fdone)
279079697Snon	struct scsi_low_softc *slp;
279179697Snon	struct targ_info *ti;
279279697Snon	int fdone;
279367468Snon{
279479697Snon	struct lun_info *li;
279567468Snon
279679697Snon	for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
279779697Snon	     li = LIST_NEXT(li, lun_chain))
279879697Snon	{
279979697Snon		scsi_low_reset_nexus_lun(slp, li, fdone);
280079697Snon		li->li_state = SCSI_LOW_LUN_SLEEP;
280179697Snon		li->li_maxnqio = 0;
280279697Snon	}
280379697Snon
280479697Snon	ti->ti_disc = 0;
280579697Snon	ti->ti_setup_msg = 0;
280679697Snon	ti->ti_setup_msg_done = 0;
280779697Snon
280879697Snon	ti->ti_osynch.offset = ti->ti_osynch.period = 0;
280979697Snon	ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
281079697Snon
281179697Snon	ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
281279697Snon	ti->ti_flags_valid &= ~SCSI_LOW_TARG_FLAGS_DISK_VALID;
281379697Snon
281479697Snon	if (slp->sl_funcs->scsi_low_targ_init != NULL)
281579697Snon	{
281679697Snon		((*slp->sl_funcs->scsi_low_targ_init)
281779697Snon			(slp, ti, SCSI_LOW_INFO_REVOKE));
281879697Snon	}
281979697Snon	scsi_low_calcf_target(ti);
282079697Snon
282179697Snon	for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
282279697Snon	     li = LIST_NEXT(li, lun_chain))
282379697Snon	{
282479697Snon		li->li_flags = 0;
282579697Snon
282679697Snon		li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
282779697Snon		li->li_flags_valid &= ~SCSI_LOW_LUN_FLAGS_DISK_VALID;
282879697Snon
282979697Snon		if (slp->sl_funcs->scsi_low_lun_init != NULL)
283079697Snon		{
283179697Snon			((*slp->sl_funcs->scsi_low_lun_init)
283279697Snon				(slp, ti, li, SCSI_LOW_INFO_REVOKE));
283379697Snon		}
283479697Snon		scsi_low_calcf_lun(li);
283579697Snon	}
283667468Snon}
283767468Snon
283867468Snonstatic void
283967468Snonscsi_low_reset_nexus(slp, fdone)
284067468Snon	struct scsi_low_softc *slp;
284167468Snon	int fdone;
284267468Snon{
284367468Snon	struct targ_info *ti;
284479697Snon	struct slccb *cb, *topcb;
284567468Snon
284679697Snon	if ((cb = slp->sl_Qnexus) != NULL)
284767468Snon	{
284879697Snon		topcb = scsi_low_revoke_ccb(slp, cb, fdone);
284967468Snon	}
285079697Snon	else
285179697Snon	{
285279697Snon		topcb = NULL;
285379697Snon	}
285467468Snon
285579697Snon	for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
285679697Snon	     ti = TAILQ_NEXT(ti, ti_chain))
285767468Snon	{
285879697Snon		scsi_low_reset_nexus_target(slp, ti, fdone);
285979697Snon		scsi_low_bus_release(slp, ti);
286067468Snon		scsi_low_init_msgsys(slp, ti);
286167468Snon	}
286267468Snon
286379697Snon	if (topcb != NULL)
286479697Snon	{
286579697Snon		topcb->ccb_flags |= CCB_STARTQ;
286679697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, topcb, ccb_chain);
286779697Snon	}
286879697Snon
286979697Snon	slp->sl_disc = 0;
287079697Snon	slp->sl_retry_sel = 0;
287167468Snon	slp->sl_flags &= ~HW_PDMASTART;
287267468Snon}
287367468Snon
287467468Snon/* misc */
287567468Snonstatic int tw_pos;
287667468Snonstatic char tw_chars[] = "|/-\\";
287779697Snon#define	TWIDDLEWAIT		10000
287867468Snon
287967468Snonstatic void
288067468Snonscsi_low_twiddle_wait(void)
288167468Snon{
288267468Snon
288367468Snon	cnputc('\b');
288467468Snon	cnputc(tw_chars[tw_pos++]);
288567468Snon	tw_pos %= (sizeof(tw_chars) - 1);
288679697Snon	SCSI_LOW_DELAY(TWIDDLEWAIT);
288767468Snon}
288867468Snon
288967468Snonvoid
289067468Snonscsi_low_bus_reset(slp)
289167468Snon	struct scsi_low_softc *slp;
289267468Snon{
289367468Snon	int i;
289467468Snon
289567468Snon	(*slp->sl_funcs->scsi_low_bus_reset) (slp);
289667468Snon
289767468Snon	printf("%s: try to reset scsi bus  ", slp->sl_xname);
289867468Snon	for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++)
289967468Snon		scsi_low_twiddle_wait();
290067468Snon	cnputc('\b');
290167468Snon	printf("\n");
290267468Snon}
290367468Snon
290467468Snonint
290567468Snonscsi_low_restart(slp, flags, s)
290667468Snon	struct scsi_low_softc *slp;
290767468Snon	int flags;
290867468Snon	u_char *s;
290967468Snon{
291067468Snon	int error;
291167468Snon
291267468Snon	if (s != NULL)
291367468Snon		printf("%s: scsi bus restart. reason: %s\n", slp->sl_xname, s);
291467468Snon
291567468Snon	if ((error = scsi_low_init(slp, flags)) != 0)
291667468Snon		return error;
291767468Snon
291867468Snon	scsi_low_start(slp);
291967468Snon	return 0;
292067468Snon}
292167468Snon
292267468Snon/**************************************************************
292367468Snon * disconnect and reselect
292467468Snon **************************************************************/
292567468Snon#define	MSGCMD_LUN(msg)	(msg & 0x07)
292667468Snon
292767468Snonstatic struct slccb *
292867468Snonscsi_low_establish_ccb(ti, li, tag)
292967468Snon	struct targ_info *ti;
293067468Snon	struct lun_info *li;
293167468Snon	scsi_low_tag_t tag;
293267468Snon{
293367468Snon	struct scsi_low_softc *slp = ti->ti_sc;
293467468Snon	struct slccb *cb;
293567468Snon
293679697Snon	if (li == NULL)
293779697Snon		return NULL;
293879697Snon
293979697Snon	cb = TAILQ_FIRST(&li->li_discq);
294071999Sphk	for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain))
294179697Snon		if (cb->ccb_tag == tag)
294267468Snon			goto found;
294367468Snon	return cb;
294467468Snon
294567468Snon	/*
294667468Snon	 * establish our ccb nexus
294767468Snon	 */
294867468Snonfound:
294979697Snon#ifdef	SCSI_LOW_DEBUG
295079697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
295179697Snon	{
295279697Snon		printf("%s: nexus(0x%lx) abort check start\n",
295379697Snon			slp->sl_xname, (u_long) cb);
295479697Snon		cb->ccb_flags |= (CCB_NORETRY | CCB_SILENT);
295579697Snon		scsi_low_revoke_ccb(slp, cb, 1);
295679697Snon		return NULL;
295779697Snon	}
295867468Snon
295979697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id) != 0)
296079697Snon	{
296179697Snon		if (cb->ccb_omsgoutflag == 0)
296279697Snon			scsi_low_ccb_message_assert(cb, SCSI_LOW_MSG_NOOP);
296379697Snon	}
296479697Snon#endif	/* SCSI_LOW_DEBUG */
296579697Snon
296679697Snon	TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
296779697Snon	cb->ccb_flags &= ~CCB_DISCQ;
296879697Snon	slp->sl_Qnexus = cb;
296979697Snon
297067468Snon	slp->sl_scp = cb->ccb_sscp;
297167468Snon	slp->sl_error |= cb->ccb_error;
297267468Snon
297367468Snon	slp->sl_disc --;
297479697Snon	ti->ti_disc --;
297567468Snon	li->li_disc --;
297667468Snon
297767468Snon	/* inform "ccb nexus established" to the host driver */
297879697Snon	(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
297979697Snon
298079697Snon	/* check msg */
298179697Snon	if (cb->ccb_msgoutflag != 0)
298279697Snon	{
298379697Snon		scsi_low_ccb_message_exec(slp, cb);
298479697Snon	}
298579697Snon
298667468Snon	return cb;
298767468Snon}
298867468Snon
298967468Snonstruct targ_info *
299067468Snonscsi_low_reselected(slp, targ)
299167468Snon	struct scsi_low_softc *slp;
299267468Snon	u_int targ;
299367468Snon{
299467468Snon	struct targ_info *ti;
299579697Snon	struct slccb *cb;
299667468Snon	u_char *s;
299767468Snon
299867468Snon	/*
299967468Snon	 * Check select vs reselected collision.
300067468Snon	 */
300167468Snon
300279697Snon	if ((cb = slp->sl_selid) != NULL)
300367468Snon	{
300479697Snon		scsi_low_arbit_fail(slp, cb);
300567468Snon#ifdef	SCSI_LOW_STATICS
300667468Snon		scsi_low_statics.nexus_conflict ++;
300767468Snon#endif	/* SCSI_LOW_STATICS */
300867468Snon	}
300979697Snon
301079697Snon	/*
301179697Snon	 * Check if no current active nexus.
301279697Snon	 */
301379697Snon	if (slp->sl_Tnexus != NULL)
301467468Snon	{
301567468Snon		s = "host busy";
301667468Snon		goto world_restart;
301767468Snon	}
301867468Snon
301967468Snon	/*
302067468Snon	 * Check a valid target id asserted ?
302167468Snon	 */
302267468Snon	if (targ >= slp->sl_ntargs || targ == slp->sl_hostid)
302367468Snon	{
302467468Snon		s = "scsi id illegal";
302567468Snon		goto world_restart;
302667468Snon	}
302767468Snon
302867468Snon	/*
302967468Snon	 * Check the target scsi status.
303067468Snon	 */
303167468Snon	ti = slp->sl_ti[targ];
303279697Snon	if (ti->ti_phase != PH_DISC && ti->ti_phase != PH_NULL)
303367468Snon	{
303467468Snon		s = "phase mismatch";
303567468Snon		goto world_restart;
303667468Snon	}
303767468Snon
303867468Snon	/*
303979697Snon	 * Setup init msgsys
304067468Snon	 */
304167468Snon	slp->sl_error = 0;
304267468Snon	scsi_low_init_msgsys(slp, ti);
304367468Snon
304467468Snon	/*
304567468Snon	 * Establish our target nexus
304667468Snon	 */
304767468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_RESEL);
304879697Snon	slp->sl_Tnexus = ti;
304967468Snon#ifdef	SCSI_LOW_STATICS
305067468Snon	scsi_low_statics.nexus_reselected ++;
305167468Snon#endif	/* SCSI_LOW_STATICS */
305267468Snon	return ti;
305367468Snon
305467468Snonworld_restart:
305567468Snon	printf("%s: reselect(%x:unknown) %s\n", slp->sl_xname, targ, s);
305667468Snon	scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
305767468Snon		         "reselect: scsi world confused");
305867468Snon	return NULL;
305967468Snon}
306067468Snon
306167468Snon/**************************************************************
306267468Snon * cmd out pointer setup
306367468Snon **************************************************************/
306467468Snonint
306567468Snonscsi_low_cmd(slp, ti)
306667468Snon	struct scsi_low_softc *slp;
306767468Snon	struct targ_info *ti;
306867468Snon{
306979697Snon	struct slccb *cb = slp->sl_Qnexus;
307067468Snon
307179697Snon	slp->sl_ph_count ++;
307267468Snon	if (cb == NULL)
307367468Snon	{
307467468Snon		/*
307579697Snon		 * no ccb, abort!
307667468Snon		 */
307767468Snon		slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd;
307867468Snon		slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd);
307967468Snon		slp->sl_scp.scp_datalen = 0;
308067468Snon		slp->sl_scp.scp_direction = SCSI_LOW_READ;
308179697Snon		slp->sl_error |= FATALIO;
308279697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
308379697Snon		SCSI_LOW_INFO(slp, ti, "CMDOUT: ccb nexus not found");
308479697Snon		return EINVAL;
308567468Snon	}
308679697Snon	else
308767468Snon	{
308879697Snon#ifdef	SCSI_LOW_DEBUG
308979697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_CMDLNK_CHECK, ti->ti_id))
309079697Snon		{
309179697Snon			scsi_low_test_cmdlnk(slp, cb);
309279697Snon		}
309379697Snon#endif	/* SCSI_LOW_DEBUG */
309467468Snon	}
309567468Snon	return 0;
309667468Snon}
309767468Snon
309867468Snon/**************************************************************
309967468Snon * data out pointer setup
310067468Snon **************************************************************/
310167468Snonint
310267468Snonscsi_low_data(slp, ti, bp, direction)
310367468Snon	struct scsi_low_softc *slp;
310467468Snon	struct targ_info *ti;
310567468Snon	struct buf **bp;
310667468Snon	int direction;
310767468Snon{
310879697Snon	struct slccb *cb = slp->sl_Qnexus;
310967468Snon
311079697Snon	if (cb != NULL && direction == cb->ccb_sscp.scp_direction)
311167468Snon	{
311279697Snon		*bp = cb->bp;
311379697Snon		return 0;
311467468Snon	}
311567468Snon
311679697Snon	slp->sl_error |= (FATALIO | PDMAERR);
311779697Snon	slp->sl_scp.scp_datalen = 0;
311879697Snon	slp->sl_scp.scp_direction = direction;
311979697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
312079697Snon	if (ti->ti_ophase != ti->ti_phase)
312167468Snon	{
312279697Snon		char *s;
312379697Snon
312479697Snon		if (cb == NULL)
312579697Snon			s = "DATA PHASE: ccb nexus not found";
312679697Snon		else
312779697Snon			s = "DATA PHASE: xfer direction mismatch";
312879697Snon		SCSI_LOW_INFO(slp, ti, s);
312967468Snon	}
313067468Snon
313179697Snon	*bp = NULL;
313279697Snon	return EINVAL;
313367468Snon}
313467468Snon
313567468Snon/**************************************************************
313667468Snon * MSG_SYS
313767468Snon **************************************************************/
313867468Snon#define	MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;}
313967468Snon#define	MSGIN_PERIOD(ti) ((ti)->ti_msgin[3])
314067468Snon#define	MSGIN_OFFSET(ti) ((ti)->ti_msgin[4])
314179697Snon#define	MSGIN_WIDTHP(ti) ((ti)->ti_msgin[3])
314267468Snon#define	MSGIN_DATA_LAST	0x30
314367468Snon
314492770Salfredstatic int scsi_low_errfunc_synch(struct scsi_low_softc *, u_int);
314592770Salfredstatic int scsi_low_errfunc_wide(struct scsi_low_softc *, u_int);
314692770Salfredstatic int scsi_low_errfunc_identify(struct scsi_low_softc *, u_int);
314792770Salfredstatic int scsi_low_errfunc_qtag(struct scsi_low_softc *, u_int);
314867468Snon
314992770Salfredstatic int scsi_low_msgfunc_synch(struct scsi_low_softc *);
315092770Salfredstatic int scsi_low_msgfunc_wide(struct scsi_low_softc *);
315192770Salfredstatic int scsi_low_msgfunc_identify(struct scsi_low_softc *);
315292770Salfredstatic int scsi_low_msgfunc_abort(struct scsi_low_softc *);
315392770Salfredstatic int scsi_low_msgfunc_qabort(struct scsi_low_softc *);
315492770Salfredstatic int scsi_low_msgfunc_qtag(struct scsi_low_softc *);
315592770Salfredstatic int scsi_low_msgfunc_reset(struct scsi_low_softc *);
315667468Snon
315767468Snonstruct scsi_low_msgout_data {
315867468Snon	u_int	md_flags;
315967468Snon	u_int8_t md_msg;
316092770Salfred	int (*md_msgfunc)(struct scsi_low_softc *);
316192770Salfred	int (*md_errfunc)(struct scsi_low_softc *, u_int);
316279697Snon#define	MSG_RELEASE_ATN	0x0001
316379697Snon	u_int md_condition;
316467468Snon};
316567468Snon
316667468Snonstruct scsi_low_msgout_data scsi_low_msgout_data[] = {
316779697Snon/* 0 */	{SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_reset, NULL, MSG_RELEASE_ATN},
316879697Snon/* 1 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL, MSG_RELEASE_ATN},
316979697Snon/* 2 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL, MSG_RELEASE_ATN},
317079697Snon/* 3 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL, MSG_RELEASE_ATN},
317179697Snon/* 4 */ {SCSI_LOW_MSG_IDENTIFY, MSG_IDENTIFY, scsi_low_msgfunc_identify, scsi_low_errfunc_identify, 0},
317279697Snon/* 5 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
317379697Snon/* 6 */ {SCSI_LOW_MSG_TERMIO, MSG_TERM_IO, NULL, NULL, MSG_RELEASE_ATN},
317479697Snon/* 7 */ {SCSI_LOW_MSG_SIMPLE_QTAG,  MSG_SIMPLE_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
317579697Snon/* 8 */ {SCSI_LOW_MSG_ORDERED_QTAG, MSG_ORDERED_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
317679697Snon/* 9 */{SCSI_LOW_MSG_HEAD_QTAG,  MSG_HEAD_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
317779697Snon/* 10 */ {SCSI_LOW_MSG_ABORT_QTAG, MSG_ABORT_QTAG, scsi_low_msgfunc_qabort, NULL,  MSG_RELEASE_ATN},
317879697Snon/* 11 */ {SCSI_LOW_MSG_CLEAR_QTAG, MSG_CLEAR_QTAG, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
317979697Snon/* 12 */{SCSI_LOW_MSG_WIDE, MSG_EXTEND, scsi_low_msgfunc_wide, scsi_low_errfunc_wide, MSG_RELEASE_ATN},
318079697Snon/* 13 */{SCSI_LOW_MSG_SYNCH, MSG_EXTEND, scsi_low_msgfunc_synch, scsi_low_errfunc_synch, MSG_RELEASE_ATN},
318179697Snon/* 14 */{SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL, MSG_RELEASE_ATN},
318279697Snon/* 15 */{SCSI_LOW_MSG_ALL, 0},
318367468Snon};
318467468Snon
318592770Salfredstatic int scsi_low_msginfunc_ext(struct scsi_low_softc *);
318692770Salfredstatic int scsi_low_synch(struct scsi_low_softc *);
318792770Salfredstatic int scsi_low_wide(struct scsi_low_softc *);
318892770Salfredstatic int scsi_low_msginfunc_msg_reject(struct scsi_low_softc *);
318992770Salfredstatic int scsi_low_msginfunc_rejop(struct scsi_low_softc *);
319092770Salfredstatic int scsi_low_msginfunc_rp(struct scsi_low_softc *);
319192770Salfredstatic int scsi_low_msginfunc_sdp(struct scsi_low_softc *);
319292770Salfredstatic int scsi_low_msginfunc_disc(struct scsi_low_softc *);
319392770Salfredstatic int scsi_low_msginfunc_cc(struct scsi_low_softc *);
319492770Salfredstatic int scsi_low_msginfunc_lcc(struct scsi_low_softc *);
319592770Salfredstatic int scsi_low_msginfunc_parity(struct scsi_low_softc *);
319692770Salfredstatic int scsi_low_msginfunc_noop(struct scsi_low_softc *);
319792770Salfredstatic int scsi_low_msginfunc_simple_qtag(struct scsi_low_softc *);
319892770Salfredstatic int scsi_low_msginfunc_i_wide_residue(struct scsi_low_softc *);
319967468Snon
320067468Snonstruct scsi_low_msgin_data {
320167468Snon	u_int md_len;
320292770Salfred	int (*md_msgfunc)(struct scsi_low_softc *);
320367468Snon};
320467468Snon
320567468Snonstruct scsi_low_msgin_data scsi_low_msgin_data[] = {
320667468Snon/* 0 */	{1,	scsi_low_msginfunc_cc},
320767468Snon/* 1 */ {2,	scsi_low_msginfunc_ext},
320867468Snon/* 2 */ {1,	scsi_low_msginfunc_sdp},
320979697Snon/* 3 */ {1,	scsi_low_msginfunc_rp},
321067468Snon/* 4 */ {1,	scsi_low_msginfunc_disc},
321167468Snon/* 5 */ {1,	scsi_low_msginfunc_rejop},
321267468Snon/* 6 */ {1,	scsi_low_msginfunc_rejop},
321367468Snon/* 7 */ {1,	scsi_low_msginfunc_msg_reject},
321467468Snon/* 8 */ {1,	scsi_low_msginfunc_noop},
321567468Snon/* 9 */ {1,	scsi_low_msginfunc_parity},
321679697Snon/* a */ {1,	scsi_low_msginfunc_lcc},
321779697Snon/* b */ {1,	scsi_low_msginfunc_lcc},
321867468Snon/* c */ {1,	scsi_low_msginfunc_rejop},
321967468Snon/* d */ {2,	scsi_low_msginfunc_rejop},
322067468Snon/* e */ {1,	scsi_low_msginfunc_rejop},
322167468Snon/* f */ {1,	scsi_low_msginfunc_rejop},
322267468Snon/* 0x10 */ {1,	scsi_low_msginfunc_rejop},
322367468Snon/* 0x11 */ {1,	scsi_low_msginfunc_rejop},
322467468Snon/* 0x12 */ {1,	scsi_low_msginfunc_rejop},
322567468Snon/* 0x13 */ {1,	scsi_low_msginfunc_rejop},
322667468Snon/* 0x14 */ {1,	scsi_low_msginfunc_rejop},
322767468Snon/* 0x15 */ {1,	scsi_low_msginfunc_rejop},
322867468Snon/* 0x16 */ {1,	scsi_low_msginfunc_rejop},
322967468Snon/* 0x17 */ {1,	scsi_low_msginfunc_rejop},
323067468Snon/* 0x18 */ {1,	scsi_low_msginfunc_rejop},
323167468Snon/* 0x19 */ {1,	scsi_low_msginfunc_rejop},
323267468Snon/* 0x1a */ {1,	scsi_low_msginfunc_rejop},
323367468Snon/* 0x1b */ {1,	scsi_low_msginfunc_rejop},
323467468Snon/* 0x1c */ {1,	scsi_low_msginfunc_rejop},
323567468Snon/* 0x1d */ {1,	scsi_low_msginfunc_rejop},
323667468Snon/* 0x1e */ {1,	scsi_low_msginfunc_rejop},
323767468Snon/* 0x1f */ {1,	scsi_low_msginfunc_rejop},
323879697Snon/* 0x20 */ {2,	scsi_low_msginfunc_simple_qtag},
323967468Snon/* 0x21 */ {2,	scsi_low_msginfunc_rejop},
324067468Snon/* 0x22 */ {2,	scsi_low_msginfunc_rejop},
324179697Snon/* 0x23 */ {2,	scsi_low_msginfunc_i_wide_residue},
324267468Snon/* 0x24 */ {2,	scsi_low_msginfunc_rejop},
324367468Snon/* 0x25 */ {2,	scsi_low_msginfunc_rejop},
324467468Snon/* 0x26 */ {2,	scsi_low_msginfunc_rejop},
324567468Snon/* 0x27 */ {2,	scsi_low_msginfunc_rejop},
324667468Snon/* 0x28 */ {2,	scsi_low_msginfunc_rejop},
324767468Snon/* 0x29 */ {2,	scsi_low_msginfunc_rejop},
324867468Snon/* 0x2a */ {2,	scsi_low_msginfunc_rejop},
324967468Snon/* 0x2b */ {2,	scsi_low_msginfunc_rejop},
325067468Snon/* 0x2c */ {2,	scsi_low_msginfunc_rejop},
325167468Snon/* 0x2d */ {2,	scsi_low_msginfunc_rejop},
325267468Snon/* 0x2e */ {2,	scsi_low_msginfunc_rejop},
325367468Snon/* 0x2f */ {2,	scsi_low_msginfunc_rejop},
325467468Snon/* 0x30 */ {1,	scsi_low_msginfunc_rejop}	/* default rej op */
325567468Snon};
325667468Snon
325767468Snon/**************************************************************
325867468Snon * msgout
325967468Snon **************************************************************/
326067468Snonstatic int
326179697Snonscsi_low_msgfunc_synch(slp)
326279697Snon	struct scsi_low_softc *slp;
326367468Snon{
326479697Snon	struct targ_info *ti = slp->sl_Tnexus;
326567468Snon	int ptr = ti->ti_msgoutlen;
326667468Snon
326767468Snon	ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN;
326867468Snon	ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE;
326973025Snon	ti->ti_msgoutstr[ptr + 3] = ti->ti_maxsynch.period;
327073025Snon	ti->ti_msgoutstr[ptr + 4] = ti->ti_maxsynch.offset;
327167468Snon	return MSG_EXTEND_SYNCHLEN + 2;
327267468Snon}
327367468Snon
327467468Snonstatic int
327579697Snonscsi_low_msgfunc_wide(slp)
327679697Snon	struct scsi_low_softc *slp;
327767468Snon{
327879697Snon	struct targ_info *ti = slp->sl_Tnexus;
327967468Snon	int ptr = ti->ti_msgoutlen;
328067468Snon
328167468Snon	ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN;
328267468Snon	ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE;
328373025Snon	ti->ti_msgoutstr[ptr + 3] = ti->ti_width;
328467468Snon	return MSG_EXTEND_WIDELEN + 2;
328567468Snon}
328667468Snon
328767468Snonstatic int
328879697Snonscsi_low_msgfunc_identify(slp)
328979697Snon	struct scsi_low_softc *slp;
329067468Snon{
329179697Snon	struct targ_info *ti = slp->sl_Tnexus;
329279697Snon	struct lun_info *li = slp->sl_Lnexus;
329379697Snon	struct slccb *cb = slp->sl_Qnexus;
329479697Snon	int ptr = ti->ti_msgoutlen;
329579697Snon	u_int8_t msg;
329667468Snon
329779697Snon	msg = MSG_IDENTIFY;
329879697Snon	if (cb == NULL)
329967468Snon	{
330079697Snon		slp->sl_error |= FATALIO;
330179697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
330279697Snon		SCSI_LOW_INFO(slp, ti, "MSGOUT: nexus unknown");
330367468Snon	}
330467468Snon	else
330567468Snon	{
330679697Snon		if (scsi_low_is_disconnect_ok(cb) != 0)
330779697Snon			msg |= (MSG_IDENTIFY_DISCPRIV | li->li_lun);
330879697Snon		else
330979697Snon			msg |= li->li_lun;
331079697Snon
331179697Snon		if (ti->ti_phase == PH_MSGOUT)
331279697Snon		{
331379697Snon			(*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
331479697Snon			if (cb->ccb_tag == SCSI_LOW_UNKTAG)
331579697Snon			{
331679697Snon				(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
331779697Snon			}
331879697Snon		}
331967468Snon	}
332079697Snon	ti->ti_msgoutstr[ptr + 0] = msg;
332167468Snon	return 1;
332267468Snon}
332367468Snon
332467468Snonstatic int
332579697Snonscsi_low_msgfunc_abort(slp)
332679697Snon	struct scsi_low_softc *slp;
332767468Snon{
332867468Snon
332979697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_ABORT);
333079697Snon	return 1;
333179697Snon}
333279697Snon
333379697Snonstatic int
333479697Snonscsi_low_msgfunc_qabort(slp)
333579697Snon	struct scsi_low_softc *slp;
333679697Snon{
333779697Snon
333879697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_TERM);
333979697Snon	return 1;
334079697Snon}
334179697Snon
334279697Snonstatic int
334379697Snonscsi_low_msgfunc_reset(slp)
334479697Snon	struct scsi_low_softc *slp;
334579697Snon{
334679697Snon
334779697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_RESET);
334879697Snon	return 1;
334979697Snon}
335079697Snon
335179697Snonstatic int
335279697Snonscsi_low_msgfunc_qtag(slp)
335379697Snon	struct scsi_low_softc *slp;
335479697Snon{
335579697Snon	struct targ_info *ti = slp->sl_Tnexus;
335679697Snon	struct slccb *cb = slp->sl_Qnexus;
335779697Snon	int ptr = ti->ti_msgoutlen;
335879697Snon
335979697Snon	if (cb == NULL || cb->ccb_tag == SCSI_LOW_UNKTAG)
336067468Snon	{
336167468Snon		ti->ti_msgoutstr[ptr + 0] = MSG_NOOP;
336267468Snon		return 1;
336367468Snon	}
336467468Snon	else
336567468Snon	{
336679697Snon		ti->ti_msgoutstr[ptr + 1] = (u_int8_t) cb->ccb_tag;
336779697Snon		if (ti->ti_phase == PH_MSGOUT)
336879697Snon		{
336979697Snon			(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
337079697Snon		}
337167468Snon	}
337279697Snon	return 2;
337367468Snon}
337467468Snon
337567468Snon/*
337667468Snon * The following functions are called when targets give unexpected
337767468Snon * responces in msgin (after msgout).
337867468Snon */
337967468Snonstatic int
338079697Snonscsi_low_errfunc_identify(slp, msgflags)
338179697Snon	struct scsi_low_softc *slp;
338267468Snon	u_int msgflags;
338367468Snon{
338467468Snon
338579697Snon	if (slp->sl_Lnexus != NULL)
338679697Snon	{
338779697Snon	        slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_DISC;
338879697Snon		scsi_low_calcf_lun(slp->sl_Lnexus);
338979697Snon	}
339067468Snon	return 0;
339167468Snon}
339267468Snon
339367468Snonstatic int
339479697Snonscsi_low_errfunc_synch(slp, msgflags)
339579697Snon	struct scsi_low_softc *slp;
339667468Snon	u_int msgflags;
339767468Snon{
339879697Snon	struct targ_info *ti = slp->sl_Tnexus;
339967468Snon
340067468Snon	MSGIN_PERIOD(ti) = 0;
340167468Snon	MSGIN_OFFSET(ti) = 0;
340279697Snon	scsi_low_synch(slp);
340367468Snon	return 0;
340467468Snon}
340567468Snon
340667468Snonstatic int
340779697Snonscsi_low_errfunc_wide(slp, msgflags)
340879697Snon	struct scsi_low_softc *slp;
340967468Snon	u_int msgflags;
341067468Snon{
341179697Snon	struct targ_info *ti = slp->sl_Tnexus;
341279697Snon
341379697Snon	MSGIN_WIDTHP(ti) = 0;
341479697Snon	scsi_low_wide(slp);
341567468Snon	return 0;
341667468Snon}
341767468Snon
341879697Snonstatic int
341979697Snonscsi_low_errfunc_qtag(slp, msgflags)
342079697Snon	struct scsi_low_softc *slp;
342179697Snon	u_int msgflags;
342279697Snon{
342379697Snon
342479697Snon	if ((msgflags & SCSI_LOW_MSG_REJECT) != 0)
342579697Snon	{
342679697Snon		if (slp->sl_Qnexus != NULL)
342779697Snon		{
342879697Snon			scsi_low_deactivate_qtag(slp->sl_Qnexus);
342979697Snon		}
343079697Snon		if (slp->sl_Lnexus != NULL)
343179697Snon		{
343279697Snon			slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_QTAG;
343379697Snon			scsi_low_calcf_lun(slp->sl_Lnexus);
343479697Snon		}
343579697Snon		printf("%s: scsi_low: qtag msg rejected\n", slp->sl_xname);
343679697Snon	}
343779697Snon	return 0;
343879697Snon}
343979697Snon
344079697Snon
344167468Snonint
344279697Snonscsi_low_msgout(slp, ti, fl)
344367468Snon	struct scsi_low_softc *slp;
344467468Snon	struct targ_info *ti;
344579697Snon	u_int fl;
344667468Snon{
344767468Snon	struct scsi_low_msgout_data *mdp;
344867468Snon	int len = 0;
344967468Snon
345079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
345179697Snon	if (ti != slp->sl_Tnexus)
345279697Snon	{
345379697Snon		scsi_low_print(slp, NULL);
345479697Snon		panic("scsi_low_msgout: Target nexus inconsistent");
345579697Snon	}
345679697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
345779697Snon
345879697Snon	slp->sl_ph_count ++;
345979697Snon	if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
346079697Snon	{
346179697Snon		printf("%s: too many phase changes\n", slp->sl_xname);
346279697Snon		slp->sl_error |= FATALIO;
346379697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
346479697Snon	}
346579697Snon
346667468Snon	/* STEP I.
346767468Snon	 * Scsi phase changes.
346867468Snon	 * Previously msgs asserted are accepted by our target or
346967468Snon	 * processed by scsi_low_msgin.
347067468Snon	 * Thus clear all saved informations.
347167468Snon	 */
347279697Snon	if ((fl & SCSI_LOW_MSGOUT_INIT) != 0)
347367468Snon	{
347467468Snon		ti->ti_omsgflags = 0;
347567468Snon		ti->ti_emsgflags = 0;
347667468Snon	}
347779697Snon	else if (slp->sl_atten == 0)
347879697Snon	{
347967468Snon	/* STEP II.
348067468Snon	 * We did not assert attention, however still our target required
348167468Snon	 * msgs. Resend previous msgs.
348267468Snon	 */
348367468Snon		ti->ti_msgflags |= ti->ti_omsgflags;
348479697Snon		ti->ti_omsgflags = 0;
348567468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
348667468Snon		printf("%s: scsi_low_msgout: retry msgout\n", slp->sl_xname);
348767468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
348867468Snon	}
348967468Snon
349067468Snon	/* STEP III.
349179697Snon	 * We have no msgs. send MSG_NOOP (OK?)
349267468Snon	 */
349379697Snon	if (scsi_low_is_msgout_continue(ti, 0) == 0)
349467468Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0);
349567468Snon
349667468Snon	/* STEP IV.
349767468Snon	 * Process all msgs
349867468Snon	 */
349967468Snon	ti->ti_msgoutlen = 0;
350079697Snon	slp->sl_clear_atten = 0;
350167468Snon	mdp = &scsi_low_msgout_data[0];
350267468Snon	for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
350367468Snon	{
350467468Snon		if ((ti->ti_msgflags & mdp->md_flags) != 0)
350567468Snon		{
350667468Snon			ti->ti_omsgflags |= mdp->md_flags;
350767468Snon			ti->ti_msgflags &= ~mdp->md_flags;
350867468Snon			ti->ti_emsgflags = mdp->md_flags;
350967468Snon
351067468Snon			ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg;
351167468Snon			if (mdp->md_msgfunc != NULL)
351279697Snon				len = (*mdp->md_msgfunc) (slp);
351367468Snon			else
351467468Snon				len = 1;
351567468Snon
351679697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
351779697Snon			scsi_low_msg_log_write(&ti->ti_log_msgout,
351879697Snon			       &ti->ti_msgoutstr[ti->ti_msgoutlen], len);
351979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
352079697Snon
352167468Snon			ti->ti_msgoutlen += len;
352279697Snon			if ((mdp->md_condition & MSG_RELEASE_ATN) != 0)
352379697Snon			{
352479697Snon				slp->sl_clear_atten = 1;
352579697Snon				break;
352679697Snon			}
352779697Snon
352879697Snon			if ((fl & SCSI_LOW_MSGOUT_UNIFY) == 0 ||
352967468Snon			    ti->ti_msgflags == 0)
353067468Snon				break;
353179697Snon
353267468Snon			if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5)
353367468Snon				break;
353467468Snon		}
353567468Snon	}
353667468Snon
353779697Snon	if (scsi_low_is_msgout_continue(ti, 0) == 0)
353879697Snon		slp->sl_clear_atten = 1;
353967468Snon
354067468Snon	return ti->ti_msgoutlen;
354167468Snon}
354267468Snon
354367468Snon/**************************************************************
354467468Snon * msgin
354567468Snon **************************************************************/
354667468Snonstatic int
354779697Snonscsi_low_msginfunc_noop(slp)
354879697Snon	struct scsi_low_softc *slp;
354967468Snon{
355067468Snon
355167468Snon	return 0;
355267468Snon}
355367468Snon
355467468Snonstatic int
355579697Snonscsi_low_msginfunc_rejop(slp)
355679697Snon	struct scsi_low_softc *slp;
355767468Snon{
355879697Snon	struct targ_info *ti = slp->sl_Tnexus;
355967468Snon	u_int8_t msg = ti->ti_msgin[0];
356067468Snon
356179697Snon	printf("%s: MSGIN: msg 0x%x rejected\n", slp->sl_xname, (u_int) msg);
356267468Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
356367468Snon	return 0;
356467468Snon}
356567468Snon
356667468Snonstatic int
356779697Snonscsi_low_msginfunc_cc(slp)
356879697Snon	struct scsi_low_softc *slp;
356967468Snon{
357079697Snon	struct lun_info *li;
357167468Snon
357267468Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC);
357379697Snon
357479697Snon	/* validate status */
357579697Snon	if (slp->sl_Qnexus == NULL)
357679697Snon		return ENOENT;
357779697Snon
357879697Snon	slp->sl_Qnexus->ccb_sscp.scp_status = slp->sl_scp.scp_status;
357979697Snon 	li = slp->sl_Lnexus;
358079697Snon	switch (slp->sl_scp.scp_status)
358179697Snon	{
358279697Snon	case ST_GOOD:
358379697Snon		li->li_maxnqio = li->li_maxnexus;
358479697Snon		break;
358579697Snon
358679697Snon	case ST_CHKCOND:
358779697Snon		li->li_maxnqio = 0;
358879697Snon		if (li->li_qflags & SCSI_LOW_QFLAG_CA_QCLEAR)
358979697Snon			scsi_low_reset_nexus_lun(slp, li, 0);
359079697Snon		break;
359179697Snon
359279697Snon	case ST_BUSY:
359379697Snon		li->li_maxnqio = 0;
359479697Snon		break;
359579697Snon
359679697Snon	case ST_QUEFULL:
359779697Snon		if (li->li_maxnexus >= li->li_nqio)
359879697Snon			li->li_maxnexus = li->li_nqio - 1;
359979697Snon		li->li_maxnqio = li->li_maxnexus;
360079697Snon		break;
360179697Snon
360279697Snon	case ST_INTERGOOD:
360379697Snon	case ST_INTERMET:
360479697Snon		slp->sl_error |= MSGERR;
360579697Snon		break;
360679697Snon
360779697Snon	default:
360879697Snon		break;
360979697Snon	}
361067468Snon	return 0;
361167468Snon}
361267468Snon
361367468Snonstatic int
361479697Snonscsi_low_msginfunc_lcc(slp)
361579697Snon	struct scsi_low_softc *slp;
361679697Snon{
361767468Snon	struct targ_info *ti;
361879697Snon	struct lun_info *li;
361979697Snon	struct slccb *ncb, *cb;
362079697Snon
362179697Snon	ti = slp->sl_Tnexus;
362279697Snon 	li = slp->sl_Lnexus;
362379697Snon	if ((cb = slp->sl_Qnexus) == NULL)
362479697Snon		goto bad;
362579697Snon
362679697Snon	cb->ccb_sscp.scp_status = slp->sl_scp.scp_status;
362779697Snon	switch (slp->sl_scp.scp_status)
362879697Snon	{
362979697Snon	case ST_INTERGOOD:
363079697Snon	case ST_INTERMET:
363179697Snon		li->li_maxnqio = li->li_maxnexus;
363279697Snon		break;
363379697Snon
363479697Snon	default:
363579697Snon		slp->sl_error |= MSGERR;
363679697Snon		break;
363779697Snon	}
363879697Snon
363979697Snon	if ((li->li_flags & SCSI_LOW_LINK) == 0)
364079697Snon		goto bad;
364179697Snon
364279697Snon	cb->ccb_error |= slp->sl_error;
364379697Snon	if (cb->ccb_error != 0)
364479697Snon		goto bad;
364579697Snon
364679697Snon	for (ncb = TAILQ_FIRST(&slp->sl_start); ncb != NULL;
364779697Snon	     ncb = TAILQ_NEXT(ncb, ccb_chain))
364879697Snon	{
364979697Snon		if (ncb->li == li)
365079697Snon			goto cmd_link_start;
365179697Snon	}
365279697Snon
365379697Snon
365479697Snonbad:
365579697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_LCTERM);
365679697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
365779697Snon	return EIO;
365879697Snon
365979697Snoncmd_link_start:
366079697Snon	ncb->ccb_flags &= ~CCB_STARTQ;
366179697Snon	TAILQ_REMOVE(&slp->sl_start, ncb, ccb_chain);
366279697Snon
366379697Snon	scsi_low_dealloc_qtag(ncb);
366479697Snon	ncb->ccb_tag = cb->ccb_tag;
366579697Snon	ncb->ccb_otag = cb->ccb_otag;
366679697Snon	cb->ccb_tag = SCSI_LOW_UNKTAG;
366779697Snon	cb->ccb_otag = SCSI_LOW_UNKTAG;
366879697Snon	if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
3669106890Simp		panic("%s: linked ccb retried", slp->sl_xname);
367079697Snon
367179697Snon	slp->sl_Qnexus = ncb;
367279697Snon	slp->sl_ph_count = 0;
367379697Snon
367479697Snon	ncb->ccb_error = 0;
367579697Snon	ncb->ccb_datalen = -1;
367679697Snon	ncb->ccb_scp.scp_status = ST_UNKNOWN;
367779697Snon	ncb->ccb_flags &= ~CCB_INTERNAL;
367879697Snon
367979697Snon	scsi_low_init_msgsys(slp, ti);
368079697Snon
368179697Snon	(*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, ncb);
368279697Snon
368379697Snon	if (ncb->ccb_tcmax < SCSI_LOW_MIN_TOUT)
368479697Snon		ncb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
368579697Snon	ncb->ccb_tc = ncb->ccb_tcmax;
368679697Snon
368779697Snon	/* setup saved scsi data pointer */
368879697Snon	ncb->ccb_sscp = ncb->ccb_scp;
368979697Snon	slp->sl_scp = ncb->ccb_sscp;
369079697Snon	slp->sl_error = ncb->ccb_error;
369179697Snon
369279697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
369379697Snon	scsi_low_msg_log_init(&ti->ti_log_msgin);
369479697Snon	scsi_low_msg_log_init(&ti->ti_log_msgout);
369579697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
369679697Snon	return EJUSTRETURN;
369779697Snon}
369879697Snon
369979697Snonstatic int
370079697Snonscsi_low_msginfunc_disc(slp)
370179697Snon	struct scsi_low_softc *slp;
370267468Snon{
370367468Snon
370467468Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC);
370567468Snon	return 0;
370667468Snon}
370767468Snon
370867468Snonstatic int
370979697Snonscsi_low_msginfunc_sdp(slp)
371079697Snon	struct scsi_low_softc *slp;
371167468Snon{
371279697Snon	struct slccb *cb = slp->sl_Qnexus;
371367468Snon
371479697Snon	if (cb != NULL)
371579697Snon	{
371679697Snon		cb->ccb_sscp.scp_datalen = slp->sl_scp.scp_datalen;
371779697Snon		cb->ccb_sscp.scp_data = slp->sl_scp.scp_data;
371879697Snon	}
371967468Snon	else
372079697Snon		scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
372167468Snon	return 0;
372267468Snon}
372367468Snon
372467468Snonstatic int
372579697Snonscsi_low_msginfunc_rp(slp)
372679697Snon	struct scsi_low_softc *slp;
372767468Snon{
372867468Snon
372979697Snon	if (slp->sl_Qnexus != NULL)
373079697Snon		slp->sl_scp = slp->sl_Qnexus->ccb_sscp;
373167468Snon	else
373279697Snon		scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
373367468Snon	return 0;
373467468Snon}
373567468Snon
373667468Snonstatic int
373779697Snonscsi_low_synch(slp)
373879697Snon	struct scsi_low_softc *slp;
373967468Snon{
374079697Snon	struct targ_info *ti = slp->sl_Tnexus;
374179697Snon	u_int period = 0, offset = 0, speed;
374267468Snon	u_char *s;
374367468Snon	int error;
374467468Snon
374579697Snon	if ((MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period &&
374679697Snon	     MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset) ||
374779697Snon	     MSGIN_OFFSET(ti) == 0)
374867468Snon	{
374967468Snon		if ((offset = MSGIN_OFFSET(ti)) != 0)
375067468Snon			period = MSGIN_PERIOD(ti);
375167468Snon		s = offset ? "synchronous" : "async";
375267468Snon	}
375367468Snon	else
375467468Snon	{
375567468Snon		/* XXX:
375667468Snon		 * Target seems to be brain damaged.
375767468Snon		 * Force async transfer.
375867468Snon		 */
375973025Snon		ti->ti_maxsynch.period = 0;
376073025Snon		ti->ti_maxsynch.offset = 0;
376167468Snon		printf("%s: target brain damaged. async transfer\n",
376267468Snon			slp->sl_xname);
376367468Snon		return EINVAL;
376467468Snon	}
376567468Snon
376673025Snon	ti->ti_maxsynch.period = period;
376773025Snon	ti->ti_maxsynch.offset = offset;
376867468Snon
376967468Snon	error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH);
377067468Snon	if (error != 0)
377167468Snon	{
377267468Snon		/* XXX:
377367468Snon		 * Current period and offset are not acceptable
377467468Snon		 * for our adapter.
377567468Snon		 * The adapter changes max synch and max offset.
377667468Snon		 */
377767468Snon		printf("%s: synch neg failed. retry synch msg neg ...\n",
377867468Snon			slp->sl_xname);
377967468Snon		return error;
378067468Snon	}
378167468Snon
378279697Snon	ti->ti_osynch = ti->ti_maxsynch;
378379697Snon	if (offset > 0)
378479697Snon	{
378579697Snon		ti->ti_setup_msg_done |= SCSI_LOW_MSG_SYNCH;
378679697Snon	}
378779697Snon
378867468Snon	/* inform data */
378979697Snon	if ((slp->sl_show_result & SHOW_SYNCH_NEG) != 0)
379067468Snon	{
379179697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
379279697Snon		struct slccb *cb = slp->sl_Qnexus;
379379697Snon
379479697Snon		if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
379579697Snon			return 0;
379679697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
379779697Snon
379879697Snon		printf("%s(%d:*): <%s> offset %d period %dns ",
379979697Snon			slp->sl_xname, ti->ti_id, s, offset, period * 4);
380079697Snon
380179697Snon		if (period != 0)
380279697Snon		{
380379697Snon			speed = 1000 * 10 / (period * 4);
380479697Snon			printf("%d.%d M/s", speed / 10, speed % 10);
380579697Snon		}
380679697Snon		printf("\n");
380767468Snon	}
380879697Snon	return 0;
380979697Snon}
381067468Snon
381179697Snonstatic int
381279697Snonscsi_low_wide(slp)
381379697Snon	struct scsi_low_softc *slp;
381479697Snon{
381579697Snon	struct targ_info *ti = slp->sl_Tnexus;
381679697Snon	int error;
381779697Snon
381879697Snon	ti->ti_width = MSGIN_WIDTHP(ti);
381979697Snon	error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_WIDE);
382079697Snon	if (error != 0)
382179697Snon	{
382279697Snon		/* XXX:
382379697Snon		 * Current width is not acceptable for our adapter.
382479697Snon		 * The adapter changes max width.
382579697Snon		 */
382679697Snon		printf("%s: wide neg failed. retry wide msg neg ...\n",
382779697Snon			slp->sl_xname);
382879697Snon		return error;
382979697Snon	}
383079697Snon
383179697Snon	ti->ti_owidth = ti->ti_width;
383279697Snon	if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
383379697Snon	{
383479697Snon		ti->ti_setup_msg_done |=
383579697Snon			(SCSI_LOW_MSG_SYNCH | SCSI_LOW_MSG_WIDE);
383679697Snon	}
383779697Snon
383879697Snon	/* inform data */
383979697Snon	if ((slp->sl_show_result & SHOW_WIDE_NEG) != 0)
384079697Snon	{
384179697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
384279697Snon		struct slccb *cb = slp->sl_Qnexus;
384379697Snon
384479697Snon		if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
384579697Snon			return 0;
384679697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
384779697Snon
384879697Snon		printf("%s(%d:*): transfer width %d bits\n",
384979697Snon			slp->sl_xname, ti->ti_id, 1 << (3 + ti->ti_width));
385079697Snon	}
385167468Snon	return 0;
385267468Snon}
385367468Snon
385467468Snonstatic int
385579697Snonscsi_low_msginfunc_simple_qtag(slp)
385679697Snon	struct scsi_low_softc *slp;
385767468Snon{
385879697Snon	struct targ_info *ti = slp->sl_Tnexus;
385979697Snon	scsi_low_tag_t etag = (scsi_low_tag_t) ti->ti_msgin[1];
386079697Snon
386179697Snon	if (slp->sl_Qnexus != NULL)
386279697Snon	{
386379697Snon		if (slp->sl_Qnexus->ccb_tag != etag)
386479697Snon		{
386579697Snon			slp->sl_error |= FATALIO;
386679697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
386779697Snon			SCSI_LOW_INFO(slp, ti, "MSGIN: qtag mismatch");
386879697Snon		}
386979697Snon	}
387079697Snon	else if (scsi_low_establish_ccb(ti, slp->sl_Lnexus, etag) == NULL)
387179697Snon	{
387279697Snon#ifdef	SCSI_LOW_DEBUG
387379697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id))
387479697Snon			return 0;
387579697Snon#endif	/* SCSI_LOW_DEBUG */
387679697Snon
387779697Snon		slp->sl_error |= FATALIO;
387879697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT_QTAG, 0);
387979697Snon		SCSI_LOW_INFO(slp, ti, "MSGIN: taged ccb not found");
388079697Snon	}
388179697Snon	return 0;
388279697Snon}
388379697Snon
388479697Snonstatic int
388579697Snonscsi_low_msginfunc_i_wide_residue(slp)
388679697Snon	struct scsi_low_softc *slp;
388779697Snon{
388879697Snon	struct targ_info *ti = slp->sl_Tnexus;
388979697Snon	struct slccb *cb = slp->sl_Qnexus;
389079697Snon	int res = (int) ti->ti_msgin[1];
389179697Snon
389279697Snon	if (cb == NULL || res <= 0 ||
389379697Snon	    (ti->ti_width == SCSI_LOW_BUS_WIDTH_16 && res > 1) ||
389479697Snon	    (ti->ti_width == SCSI_LOW_BUS_WIDTH_32 && res > 3))
389579697Snon		return EINVAL;
389679697Snon
389779697Snon	if (slp->sl_scp.scp_datalen + res > cb->ccb_scp.scp_datalen)
389879697Snon		return EINVAL;
389979697Snon
390079697Snon	slp->sl_scp.scp_datalen += res;
390179697Snon	slp->sl_scp.scp_data -= res;
390279697Snon	scsi_low_data_finish(slp);
390379697Snon	return 0;
390479697Snon}
390579697Snon
390679697Snonstatic int
390779697Snonscsi_low_msginfunc_ext(slp)
390879697Snon	struct scsi_low_softc *slp;
390979697Snon{
391079697Snon	struct slccb *cb = slp->sl_Qnexus;
391179697Snon	struct lun_info *li = slp->sl_Lnexus;
391279697Snon	struct targ_info *ti = slp->sl_Tnexus;
391367468Snon	int count, retry;
391467468Snon	u_int32_t *ptr;
391567468Snon
391667468Snon	if (ti->ti_msginptr == 2)
391767468Snon	{
391867468Snon		ti->ti_msginlen = ti->ti_msgin[1] + 2;
391967468Snon		return 0;
392067468Snon	}
392167468Snon
392267468Snon	switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2]))
392367468Snon	{
392467468Snon	case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE):
392567468Snon		if (cb == NULL)
392667468Snon			break;
392767468Snon
392867468Snon		ptr = (u_int32_t *)(&ti->ti_msgin[3]);
392967468Snon		count = (int) htonl((long) (*ptr));
393067468Snon		if(slp->sl_scp.scp_datalen - count < 0 ||
393167468Snon		   slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen)
393267468Snon			break;
393367468Snon
393467468Snon		slp->sl_scp.scp_datalen -= count;
393567468Snon		slp->sl_scp.scp_data += count;
393667468Snon		return 0;
393767468Snon
393867468Snon	case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE):
393967468Snon		if (li == NULL)
394067468Snon			break;
394167468Snon
394279697Snon		retry = scsi_low_synch(slp);
394367468Snon		if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0)
394467468Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0);
394579697Snon
394679697Snon#ifdef	SCSI_LOW_DEBUG
394779697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
394879697Snon		{
394979697Snon			scsi_low_test_atten(slp, ti, SCSI_LOW_MSG_SYNCH);
395079697Snon		}
395179697Snon#endif	/* SCSI_LOW_DEBUG */
395267468Snon		return 0;
395367468Snon
395467468Snon	case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE):
395567468Snon		if (li == NULL)
395667468Snon			break;
395767468Snon
395879697Snon		retry = scsi_low_wide(slp);
395979697Snon		if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_WIDE) == 0)
396079697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0);
396179697Snon
396267468Snon		return 0;
396367468Snon
396467468Snon	default:
396567468Snon		break;
396667468Snon	}
396767468Snon
396867468Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
396967468Snon	return EINVAL;
397067468Snon}
397167468Snon
397267468Snonstatic int
397379697Snonscsi_low_msginfunc_parity(slp)
397479697Snon	struct scsi_low_softc *slp;
397567468Snon{
397679697Snon	struct targ_info *ti = slp->sl_Tnexus;
397767468Snon
397879697Snon	/* only I -> T, invalid! */
397979697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
398067468Snon	return 0;
398167468Snon}
398267468Snon
398367468Snonstatic int
398479697Snonscsi_low_msginfunc_msg_reject(slp)
398579697Snon	struct scsi_low_softc *slp;
398667468Snon{
398779697Snon	struct targ_info *ti = slp->sl_Tnexus;
398867468Snon	struct scsi_low_msgout_data *mdp;
398967468Snon	u_int msgflags;
399067468Snon
399179697Snon	if (ti->ti_emsgflags != 0)
399267468Snon	{
399379697Snon		printf("%s: msg flags [0x%x] rejected\n",
399479697Snon		       slp->sl_xname, ti->ti_emsgflags);
399567468Snon		msgflags = SCSI_LOW_MSG_REJECT;
399667468Snon		mdp = &scsi_low_msgout_data[0];
399767468Snon		for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
399867468Snon		{
399967468Snon			if ((ti->ti_emsgflags & mdp->md_flags) != 0)
400067468Snon			{
400167468Snon				ti->ti_emsgflags &= ~mdp->md_flags;
400267468Snon				if (mdp->md_errfunc != NULL)
400379697Snon					(*mdp->md_errfunc) (slp, msgflags);
400467468Snon				break;
400567468Snon			}
400667468Snon		}
400779697Snon		return 0;
400867468Snon	}
400979697Snon	else
401079697Snon	{
401179697Snon		SCSI_LOW_INFO(slp, ti, "MSGIN: rejected msg not found");
401279697Snon		slp->sl_error |= MSGERR;
401379697Snon	}
401479697Snon	return EINVAL;
401567468Snon}
401667468Snon
401779697Snonint
401867468Snonscsi_low_msgin(slp, ti, c)
401967468Snon	struct scsi_low_softc *slp;
402067468Snon	struct targ_info *ti;
402179697Snon	u_int c;
402267468Snon{
402367468Snon	struct scsi_low_msgin_data *sdp;
402467468Snon	struct lun_info *li;
402567468Snon	u_int8_t msg;
402667468Snon
402779697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
402879697Snon	if (ti != slp->sl_Tnexus)
402979697Snon	{
403079697Snon		scsi_low_print(slp, NULL);
403179697Snon		panic("scsi_low_msgin: Target nexus inconsistent");
403279697Snon	}
403379697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
403479697Snon
403567468Snon	/*
403667468Snon	 * Phase changes, clear the pointer.
403767468Snon	 */
403867468Snon	if (ti->ti_ophase != ti->ti_phase)
403967468Snon	{
404067468Snon		MSGINPTR_CLR(ti);
404179697Snon		ti->ti_msgin_parity_error = 0;
404279697Snon
404379697Snon		slp->sl_ph_count ++;
404479697Snon		if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
404579697Snon		{
404679697Snon			printf("%s: too many phase changes\n", slp->sl_xname);
404779697Snon			slp->sl_error |= FATALIO;
404879697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
404979697Snon		}
405067468Snon	}
405167468Snon
405267468Snon	/*
405367468Snon	 * Store a current messages byte into buffer and
405467468Snon	 * wait for the completion of the current msg.
405567468Snon	 */
405679697Snon	ti->ti_msgin[ti->ti_msginptr ++] = (u_int8_t) c;
405767468Snon	if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN)
405867468Snon	{
405967468Snon		ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1;
406067468Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
406167468Snon	}
406267468Snon
406367468Snon	/*
406479697Snon	 * Check parity errors.
406579697Snon	 */
406679697Snon	if ((c & SCSI_LOW_DATA_PE) != 0)
406779697Snon	{
406879697Snon		ti->ti_msgin_parity_error ++;
406979697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
407079697Snon		goto out;
407179697Snon	}
407279697Snon
407379697Snon	if (ti->ti_msgin_parity_error != 0)
407479697Snon		goto out;
407579697Snon
407679697Snon	/*
407767468Snon	 * Calculate messages length.
407867468Snon	 */
407967468Snon	msg = ti->ti_msgin[0];
408067468Snon	if (msg < MSGIN_DATA_LAST)
408167468Snon		sdp = &scsi_low_msgin_data[msg];
408267468Snon	else
408367468Snon		sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST];
408467468Snon
408567468Snon	if (ti->ti_msginlen == 0)
408667468Snon	{
408767468Snon		ti->ti_msginlen = sdp->md_len;
408867468Snon	}
408967468Snon
409067468Snon	/*
409167468Snon	 * Check comletion.
409267468Snon	 */
409367468Snon	if (ti->ti_msginptr < ti->ti_msginlen)
409479697Snon		return EJUSTRETURN;
409567468Snon
409667468Snon	/*
409767468Snon	 * Do process.
409867468Snon	 */
409967468Snon	if ((msg & MSG_IDENTIFY) == 0)
410067468Snon	{
410179697Snon		if (((*sdp->md_msgfunc) (slp)) == EJUSTRETURN)
410279697Snon			return EJUSTRETURN;
410367468Snon	}
410467468Snon	else
410567468Snon	{
410679697Snon		li = slp->sl_Lnexus;
410767468Snon		if (li == NULL)
410867468Snon		{
410979697Snon			li = scsi_low_alloc_li(ti, MSGCMD_LUN(msg), 0);
411067468Snon			if (li == NULL)
411167468Snon				goto badlun;
411279697Snon			slp->sl_Lnexus = li;
411379697Snon			(*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
411467468Snon		}
411579697Snon		else
411679697Snon		{
411779697Snon			if (MSGCMD_LUN(msg) != li->li_lun)
411879697Snon				goto badlun;
411979697Snon		}
412067468Snon
412179697Snon		if (slp->sl_Qnexus == NULL && li->li_nqio == 0)
412267468Snon		{
412367468Snon			if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG))
412479697Snon			{
412579697Snon#ifdef	SCSI_LOW_DEBUG
412679697Snon				if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
412779697Snon				{
412879697Snon					goto out;
412979697Snon				}
413079697Snon#endif	/* SCSI_LOW_DEBUG */
413167468Snon				goto badlun;
413279697Snon			}
413367468Snon		}
413467468Snon	}
413579697Snon	goto out;
413667468Snon
413767468Snon	/*
413879697Snon	 * Msg process completed, reset msgin pointer and assert ATN if desired.
413967468Snon	 */
414079697Snonbadlun:
414179697Snon	slp->sl_error |= FATALIO;
414279697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
414379697Snon	SCSI_LOW_INFO(slp, ti, "MSGIN: identify wrong");
414479697Snon
414579697Snonout:
414679697Snon	if (ti->ti_msginptr < ti->ti_msginlen)
414779697Snon		return EJUSTRETURN;
414879697Snon
414979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
415079697Snon	scsi_low_msg_log_write(&ti->ti_log_msgin,
415179697Snon			       &ti->ti_msgin[0], ti->ti_msginlen);
415279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
415379697Snon
415479697Snon	MSGINPTR_CLR(ti);
415579697Snon	return 0;
415679697Snon}
415779697Snon
415879697Snon/**********************************************************
415979697Snon * disconnect
416079697Snon **********************************************************/
416179697Snonint
416279697Snonscsi_low_disconnected(slp, ti)
416379697Snon	struct scsi_low_softc *slp;
416479697Snon	struct targ_info *ti;
416579697Snon{
416679697Snon	struct slccb *cb = slp->sl_Qnexus;
416779697Snon
416879697Snon	/* check phase completion */
416979697Snon	switch (slp->sl_msgphase)
417067468Snon	{
417179697Snon	case MSGPH_RESET:
417279697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
417379697Snon		scsi_low_msginfunc_cc(slp);
417479697Snon		scsi_low_reset_nexus_target(slp, slp->sl_Tnexus, 0);
417579697Snon		goto io_resume;
417667468Snon
417779697Snon	case MSGPH_ABORT:
417879697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
417979697Snon		scsi_low_msginfunc_cc(slp);
418079697Snon		scsi_low_reset_nexus_lun(slp, slp->sl_Lnexus, 0);
418179697Snon		goto io_resume;
418279697Snon
418379697Snon	case MSGPH_TERM:
418479697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
418579697Snon		scsi_low_msginfunc_cc(slp);
418679697Snon		goto io_resume;
418779697Snon
418879697Snon	case MSGPH_DISC:
418979697Snon		if (cb != NULL)
419067468Snon		{
419179697Snon			struct lun_info *li;
419279697Snon
419379697Snon			li = cb->li;
419479697Snon			TAILQ_INSERT_TAIL(&li->li_discq, cb, ccb_chain);
419579697Snon			cb->ccb_flags |= CCB_DISCQ;
419679697Snon			cb->ccb_error |= slp->sl_error;
419779697Snon			li->li_disc ++;
419879697Snon			ti->ti_disc ++;
419979697Snon			slp->sl_disc ++;
420079697Snon		}
420179697Snon
420279697Snon#ifdef	SCSI_LOW_STATICS
420379697Snon		scsi_low_statics.nexus_disconnected ++;
420479697Snon#endif	/* SCSI_LOW_STATICS */
420579697Snon
420679697Snon#ifdef	SCSI_LOW_DEBUG
420779697Snon		if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DISC, ti->ti_id) != 0)
420879697Snon		{
420979697Snon			printf("## SCSI_LOW_DISCONNECTED ===============\n");
421079697Snon			scsi_low_print(slp, NULL);
421179697Snon		}
421279697Snon#endif	/* SCSI_LOW_DEBUG */
421379697Snon		break;
421479697Snon
421579697Snon	case MSGPH_NULL:
421679697Snon		slp->sl_error |= FATALIO;
421779697Snon		if (ti->ti_phase == PH_SELSTART)
421879697Snon			slp->sl_error |= SELTIMEOUTIO;
421979697Snon		else
422079697Snon			slp->sl_error |= UBFERR;
422179697Snon		/* fall through */
422279697Snon
422379697Snon	case MSGPH_LCTERM:
422479697Snon	case MSGPH_CMDC:
422579697Snonio_resume:
422679697Snon		if (cb == NULL)
422779697Snon			break;
422879697Snon
422979697Snon#ifdef	SCSI_LOW_DEBUG
423079697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
423179697Snon		{
423279697Snon			if (cb->ccb_omsgoutflag == SCSI_LOW_MSG_NOOP &&
423379697Snon			    (cb->ccb_msgoutflag != 0 ||
423479697Snon			     (ti->ti_msgflags & SCSI_LOW_MSG_NOOP)))
423579697Snon			{
423679697Snon				scsi_low_info(slp, ti, "ATTEN CHECK FAILED");
423779697Snon			}
423879697Snon		}
423979697Snon#endif	/* SCSI_LOW_DEBUG */
424079697Snon
424179697Snon		cb->ccb_error |= slp->sl_error;
424279697Snon		if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
424379697Snon		{
424479697Snon			cb->ccb_flags |= CCB_STARTQ;
424579697Snon			TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
424679697Snon		}
424779697Snon		break;
424879697Snon	}
424979697Snon
425079697Snon	scsi_low_bus_release(slp, ti);
425179697Snon	scsi_low_start(slp);
425279697Snon	return 1;
425379697Snon}
425479697Snon
425579697Snon/**********************************************************
425679697Snon * TAG operations
425779697Snon **********************************************************/
4258104094Sphkstatic int
425979697Snonscsi_low_alloc_qtag(cb)
426079697Snon	struct slccb *cb;
426179697Snon{
426279697Snon	struct lun_info *li = cb->li;
426379697Snon	scsi_low_tag_t etag;
426479697Snon
426579697Snon	if (cb->ccb_otag != SCSI_LOW_UNKTAG)
426679697Snon		return 0;
426779697Snon
426879697Snon#ifndef	SCSI_LOW_ALT_QTAG_ALLOCATE
426979697Snon	etag = ffs(li->li_qtagbits);
427079697Snon	if (etag == 0)
427179697Snon		return ENOSPC;
427279697Snon
427379697Snon	li->li_qtagbits &= ~(1 << (etag - 1));
427479697Snon	cb->ccb_otag = etag;
427579697Snon	return 0;
427679697Snon
427779697Snon#else	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
427879697Snon	for (etag = li->li_qd ; li->li_qd < SCSI_LOW_MAXNEXUS; li->li_qd ++)
427979697Snon		if (li->li_qtagarray[li->li_qd] == 0)
428079697Snon			goto found;
428179697Snon
428279697Snon	for (li->li_qd = 0; li->li_qd < etag; li->li_qd ++)
428379697Snon		if (li->li_qtagarray[li->li_qd] == 0)
428479697Snon			goto found;
428579697Snon
428679697Snon	return ENOSPC;
428779697Snon
428879697Snonfound:
428979697Snon	li->li_qtagarray[li->li_qd] ++;
429079697Snon	cb->ccb_otag = (li->li_qd ++);
429179697Snon	return 0;
429279697Snon#endif	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
429379697Snon}
429479697Snon
4295104094Sphkstatic int
429679697Snonscsi_low_dealloc_qtag(cb)
429779697Snon	struct slccb *cb;
429879697Snon{
429979697Snon	struct lun_info *li = cb->li;
430079697Snon	scsi_low_tag_t etag;
430179697Snon
430279697Snon	if (cb->ccb_otag == SCSI_LOW_UNKTAG)
430379697Snon		return 0;
430479697Snon
430579697Snon#ifndef	SCSI_LOW_ALT_QTAG_ALLOCATE
430679697Snon	etag = cb->ccb_otag - 1;
430767468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
430879697Snon	if (etag >= sizeof(li->li_qtagbits) * NBBY)
430979697Snon		panic("scsi_low_dealloc_tag: illegal tag");
431067468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
431179697Snon	li->li_qtagbits |= (1 << etag);
431279697Snon
431379697Snon#else	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
431479697Snon	etag = cb->ccb_otag;
431579697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
431679697Snon	if (etag >= SCSI_LOW_MAXNEXUS)
431779697Snon		panic("scsi_low_dealloc_tag: illegal tag");
431879697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
431979697Snon	li->li_qtagarray[etag] --;
432079697Snon#endif	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
432179697Snon
432279697Snon	cb->ccb_otag = SCSI_LOW_UNKTAG;
432379697Snon	return 0;
432479697Snon}
432579697Snon
4326104094Sphkstatic struct slccb *
432779697Snonscsi_low_revoke_ccb(slp, cb, fdone)
432879697Snon	struct scsi_low_softc *slp;
432979697Snon	struct slccb *cb;
433079697Snon	int fdone;
433179697Snon{
433279697Snon	struct targ_info *ti = cb->ti;
433379697Snon	struct lun_info *li = cb->li;
433479697Snon
433579697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
433679697Snon	if ((cb->ccb_flags & (CCB_STARTQ | CCB_DISCQ)) ==
433779697Snon	    (CCB_STARTQ | CCB_DISCQ))
433879697Snon	{
4339106890Simp		panic("%s: ccb in both queue", slp->sl_xname);
434067468Snon	}
434179697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
434267468Snon
434379697Snon	if ((cb->ccb_flags & CCB_STARTQ) != 0)
434479697Snon	{
434579697Snon		TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
434679697Snon	}
434779697Snon
434879697Snon	if ((cb->ccb_flags & CCB_DISCQ) != 0)
434979697Snon	{
435079697Snon		TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
435179697Snon		li->li_disc --;
435279697Snon		ti->ti_disc --;
435379697Snon		slp->sl_disc --;
435479697Snon	}
435579697Snon
435679697Snon	cb->ccb_flags &= ~(CCB_STARTQ | CCB_DISCQ |
435779697Snon			   CCB_SENSE | CCB_CLEARQ | CCB_INTERNAL);
435879697Snon
435979697Snon	if (fdone != 0 &&
436079697Snon	    (cb->ccb_rcnt ++ >= slp->sl_max_retry ||
436179697Snon	     (cb->ccb_flags & CCB_NORETRY) != 0))
436279697Snon	{
436379697Snon		cb->ccb_error |= FATALIO;
436479697Snon		cb->ccb_flags &= ~CCB_AUTOSENSE;
436579697Snon		if (scsi_low_done(slp, cb) != SCSI_LOW_DONE_COMPLETE)
4366106890Simp			panic("%s: done ccb retried", slp->sl_xname);
436779697Snon		return NULL;
436879697Snon	}
436979697Snon	else
437079697Snon	{
437179697Snon		cb->ccb_error |= PENDINGIO;
437279697Snon		scsi_low_deactivate_qtag(cb);
437379697Snon		scsi_low_ccb_message_retry(cb);
437479697Snon		cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
437579697Snon		return cb;
437679697Snon	}
437767468Snon}
437867468Snon
4379104094Sphkstatic void
438079697Snonscsi_low_reset_nexus_lun(slp, li, fdone)
438179697Snon	struct scsi_low_softc *slp;
438279697Snon	struct lun_info *li;
438379697Snon	int fdone;
438479697Snon{
438579697Snon	struct slccb *cb, *ncb, *ecb;
438679697Snon
438779697Snon	if (li == NULL)
438879697Snon		return;
438979697Snon
439079697Snon	ecb = NULL;
439179697Snon	for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = ncb)
439279697Snon	{
439379697Snon		ncb = TAILQ_NEXT(cb, ccb_chain);
439479697Snon		cb = scsi_low_revoke_ccb(slp, cb, fdone);
439579697Snon		if (cb != NULL)
439679697Snon		{
439779697Snon			/*
439879697Snon			 * presumely keep ordering of io
439979697Snon			 */
440079697Snon			cb->ccb_flags |= CCB_STARTQ;
440179697Snon			if (ecb == NULL)
440279697Snon			{
440379697Snon				TAILQ_INSERT_HEAD(&slp->sl_start,\
440479697Snon						  cb, ccb_chain);
440579697Snon			}
440679697Snon			else
440779697Snon			{
440879697Snon				TAILQ_INSERT_AFTER(&slp->sl_start,\
440979697Snon						   ecb, cb, ccb_chain);
441079697Snon			}
441179697Snon			ecb = cb;
441279697Snon		}
441379697Snon	}
441479697Snon}
441579697Snon
441667468Snon/**************************************************************
441767468Snon * Qurik setup
441867468Snon **************************************************************/
441967468Snonstatic void
442079697Snonscsi_low_calcf_lun(li)
442167468Snon	struct lun_info *li;
442267468Snon{
442379697Snon	struct targ_info *ti = li->li_ti;
442467468Snon	struct scsi_low_softc *slp = ti->ti_sc;
442579697Snon	u_int cfgflags, diskflags;
442667468Snon
442779697Snon	if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID)
442879697Snon		cfgflags = li->li_cfgflags;
442979697Snon	else
443079697Snon		cfgflags = 0;
443179697Snon
443279697Snon	diskflags = li->li_diskflags & li->li_quirks;
443379697Snon
443479697Snon	/* disconnect */
443567468Snon	li->li_flags &= ~SCSI_LOW_DISC;
443667468Snon	if ((slp->sl_cfgflags & CFG_NODISC) == 0 &&
443779697Snon	    (diskflags & SCSI_LOW_DISK_DISC) != 0 &&
443879697Snon	    (cfgflags & SCSI_LOW_DISC) != 0)
443967468Snon		li->li_flags |= SCSI_LOW_DISC;
444067468Snon
444179697Snon	/* parity */
444267468Snon	li->li_flags |= SCSI_LOW_NOPARITY;
444367468Snon	if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 &&
444479697Snon	    (diskflags & SCSI_LOW_DISK_PARITY) != 0 &&
444579697Snon	    (cfgflags & SCSI_LOW_NOPARITY) == 0)
444667468Snon		li->li_flags &= ~SCSI_LOW_NOPARITY;
444767468Snon
444879697Snon	/* qtag */
444979697Snon	if ((slp->sl_cfgflags & CFG_NOQTAG) == 0 &&
445079697Snon	    (cfgflags & SCSI_LOW_QTAG) != 0 &&
445179697Snon	    (diskflags & SCSI_LOW_DISK_QTAG) != 0)
445279697Snon	{
445379697Snon		li->li_flags |= SCSI_LOW_QTAG;
445479697Snon		li->li_maxnexus = SCSI_LOW_MAXNEXUS;
445579697Snon		li->li_maxnqio = li->li_maxnexus;
445679697Snon	}
445779697Snon	else
445879697Snon	{
445979697Snon		li->li_flags &= ~SCSI_LOW_QTAG;
446079697Snon		li->li_maxnexus = 0;
446179697Snon		li->li_maxnqio = li->li_maxnexus;
446279697Snon	}
446379697Snon
446479697Snon	/* cmd link */
446579697Snon	li->li_flags &= ~SCSI_LOW_LINK;
446679697Snon	if ((cfgflags & SCSI_LOW_LINK) != 0 &&
446779697Snon	    (diskflags & SCSI_LOW_DISK_LINK) != 0)
446879697Snon		li->li_flags |= SCSI_LOW_LINK;
446979697Snon
447079697Snon	/* compatible flags */
447167468Snon	li->li_flags &= ~SCSI_LOW_SYNC;
447279697Snon	if (ti->ti_maxsynch.offset > 0)
447379697Snon		li->li_flags |= SCSI_LOW_SYNC;
447479697Snon
447579697Snon#ifdef	SCSI_LOW_DEBUG
447679697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
447767468Snon	{
447879697Snon		scsi_low_calcf_show(li);
447967468Snon	}
448079697Snon#endif	/* SCSI_LOW_DEBUG */
448179697Snon}
448279697Snon
448379697Snonstatic void
448479697Snonscsi_low_calcf_target(ti)
448579697Snon	struct targ_info *ti;
448679697Snon{
448779697Snon	struct scsi_low_softc *slp = ti->ti_sc;
448879697Snon	u_int offset, period, diskflags;
448979697Snon
449079697Snon	diskflags = ti->ti_diskflags & ti->ti_quirks;
449179697Snon
449279697Snon	/* synch */
449379697Snon	if ((slp->sl_cfgflags & CFG_ASYNC) == 0 &&
449479697Snon	    (diskflags & SCSI_LOW_DISK_SYNC) != 0)
449579697Snon	{
449679697Snon		offset = ti->ti_maxsynch.offset;
449779697Snon		period = ti->ti_maxsynch.period;
449879697Snon		if (offset == 0 || period == 0)
449979697Snon			offset = period = 0;
450079697Snon	}
450167468Snon	else
450279697Snon	{
450379697Snon		offset = period = 0;
450479697Snon	}
450567468Snon
450679697Snon	ti->ti_maxsynch.offset = offset;
450779697Snon	ti->ti_maxsynch.period = period;
450879697Snon
450979697Snon	/* wide */
451079697Snon	if ((diskflags & SCSI_LOW_DISK_WIDE_32) == 0 &&
451179697Snon	     ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
451279697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_16;
451379697Snon
451479697Snon	if ((diskflags & SCSI_LOW_DISK_WIDE_16) == 0 &&
451579697Snon	    ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
451679697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
451779697Snon
451879697Snon	if (ti->ti_flags_valid == SCSI_LOW_TARG_FLAGS_ALL_VALID)
451967468Snon	{
452079697Snon		if (ti->ti_maxsynch.offset != ti->ti_osynch.offset ||
452179697Snon		    ti->ti_maxsynch.period != ti->ti_osynch.period)
452279697Snon			ti->ti_setup_msg |= SCSI_LOW_MSG_SYNCH;
452379697Snon		if (ti->ti_width != ti->ti_owidth)
452479697Snon			ti->ti_setup_msg |= (SCSI_LOW_MSG_WIDE | SCSI_LOW_MSG_SYNCH);
452579697Snon
452679697Snon		ti->ti_osynch = ti->ti_maxsynch;
452779697Snon		ti->ti_owidth = ti->ti_width;
452867468Snon	}
452967468Snon
453079697Snon#ifdef	SCSI_LOW_DEBUG
453179697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
453279697Snon	{
453379697Snon		printf("%s(%d:*): max period(%dns) offset(%d) width(%d)\n",
453479697Snon			slp->sl_xname, ti->ti_id,
453579697Snon			ti->ti_maxsynch.period * 4,
453679697Snon			ti->ti_maxsynch.offset,
453779697Snon			ti->ti_width);
453879697Snon	}
453979697Snon#endif	/* SCSI_LOW_DEBUG */
454067468Snon}
454167468Snon
454279697Snonstatic void
454379697Snonscsi_low_calcf_show(li)
454479697Snon	struct lun_info *li;
454579697Snon{
454679697Snon	struct targ_info *ti = li->li_ti;
454779697Snon	struct scsi_low_softc *slp = ti->ti_sc;
454879697Snon
454979697Snon	printf("%s(%d:%d): period(%d ns) offset(%d) width(%d) flags 0x%b\n",
455079697Snon		slp->sl_xname, ti->ti_id, li->li_lun,
455179697Snon		ti->ti_maxsynch.period * 4,
455279697Snon		ti->ti_maxsynch.offset,
455379697Snon		ti->ti_width,
455479697Snon		li->li_flags, SCSI_LOW_BITS);
455579697Snon}
455679697Snon
455779697Snon#ifdef	SCSI_LOW_START_UP_CHECK
455879697Snon/**************************************************************
455979697Snon * scsi world start up
456079697Snon **************************************************************/
456192770Salfredstatic int scsi_low_poll(struct scsi_low_softc *, struct slccb *);
456279697Snon
456367468Snonstatic int
456479697Snonscsi_low_start_up(slp)
456579697Snon	struct scsi_low_softc *slp;
456667468Snon{
456767468Snon	struct targ_info *ti;
456867468Snon	struct lun_info *li;
456979697Snon	struct slccb *cb;
457079697Snon	int target, lun;
457167468Snon
457279697Snon	printf("%s: scsi_low: probing all devices ....\n", slp->sl_xname);
457367468Snon
457479697Snon	for (target = 0; target < slp->sl_ntargs; target ++)
457579697Snon	{
457679697Snon		if (target == slp->sl_hostid)
457779697Snon		{
457879697Snon			if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
457979697Snon			{
458079697Snon				printf("%s: scsi_low: target %d (host card)\n",
458179697Snon					slp->sl_xname, target);
458279697Snon			}
458379697Snon			continue;
458479697Snon		}
458567468Snon
458679697Snon		if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
458779697Snon		{
458879697Snon			printf("%s: scsi_low: target %d lun ",
458979697Snon				slp->sl_xname, target);
459079697Snon		}
459167468Snon
459279697Snon		ti = slp->sl_ti[target];
459379697Snon		for (lun = 0; lun < slp->sl_nluns; lun ++)
459479697Snon		{
459579697Snon			if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
459679697Snon				break;
459779697Snon
459879697Snon			cb->osdep = NULL;
459979697Snon			cb->bp = NULL;
460079697Snon
460179697Snon			li = scsi_low_alloc_li(ti, lun, 1);
460279697Snon
460379697Snon			scsi_low_enqueue(slp, ti, li, cb,
460479697Snon					 CCB_AUTOSENSE | CCB_POLLED, 0);
460579697Snon
460679697Snon			scsi_low_poll(slp, cb);
460779697Snon
460879697Snon			if (li->li_state != SCSI_LOW_LUN_OK)
460979697Snon				break;
461079697Snon
461179697Snon			if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
461279697Snon			{
461379697Snon				printf("%d ", lun);
461479697Snon			}
461579697Snon		}
461679697Snon
461779697Snon		if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
461879697Snon		{
461979697Snon			printf("\n");
462079697Snon		}
462179697Snon	}
462267468Snon	return 0;
462367468Snon}
462467468Snon
462579697Snonstatic int
462679697Snonscsi_low_poll(slp, cb)
462779697Snon	struct scsi_low_softc *slp;
462879697Snon	struct slccb *cb;
462979697Snon{
463079697Snon	int tcount;
463179697Snon
463279697Snon	tcount = 0;
463379697Snon	while (slp->sl_nio > 0)
463479697Snon	{
463579697Snon		SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_POLL_HZ);
463679697Snon
463779697Snon		(*slp->sl_funcs->scsi_low_poll) (slp);
463879697Snon		if (tcount ++ < SCSI_LOW_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
463979697Snon			continue;
464079697Snon
464179697Snon		tcount = 0;
464279697Snon		scsi_low_timeout_check(slp);
464379697Snon	}
464479697Snon
464579697Snon	return 0;
464679697Snon}
464779697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
464879697Snon
464967468Snon/**********************************************************
465067468Snon * DEBUG SECTION
465167468Snon **********************************************************/
465279697Snon#ifdef	SCSI_LOW_DEBUG
465367468Snonstatic void
465479697Snonscsi_low_test_abort(slp, ti, li)
465579697Snon	struct scsi_low_softc *slp;
465679697Snon	struct targ_info *ti;
465779697Snon	struct lun_info *li;
465879697Snon{
465979697Snon	struct slccb *acb;
466079697Snon
466179697Snon	if (li->li_disc > 1)
466279697Snon	{
466379697Snon		acb = TAILQ_FIRST(&li->li_discq);
466479697Snon		if (scsi_low_abort_ccb(slp, acb) == 0)
466579697Snon		{
466679697Snon			printf("%s: aborting ccb(0x%lx) start\n",
466779697Snon				slp->sl_xname, (u_long) acb);
466879697Snon		}
466979697Snon	}
467079697Snon}
467179697Snon
467279697Snonstatic void
467379697Snonscsi_low_test_atten(slp, ti, msg)
467479697Snon	struct scsi_low_softc *slp;
467579697Snon	struct targ_info *ti;
467679697Snon	u_int msg;
467779697Snon{
467879697Snon
467979697Snon	if (slp->sl_ph_count < SCSI_LOW_MAX_ATTEN_CHECK)
468079697Snon		scsi_low_assert_msg(slp, ti, msg, 0);
468179697Snon	else
468279697Snon		printf("%s: atten check OK\n", slp->sl_xname);
468379697Snon}
468479697Snon
468579697Snonstatic void
468679697Snonscsi_low_test_cmdlnk(slp, cb)
468779697Snon	struct scsi_low_softc *slp;
468879697Snon	struct slccb *cb;
468979697Snon{
469079697Snon#define	SCSI_LOW_CMDLNK_NOK	(CCB_INTERNAL | CCB_SENSE | CCB_CLEARQ)
469179697Snon
469279697Snon	if ((cb->ccb_flags & SCSI_LOW_CMDLNK_NOK) != 0)
469379697Snon		return;
469479697Snon
469579697Snon	memcpy(cb->ccb_scsi_cmd, slp->sl_scp.scp_cmd,
469679697Snon	       slp->sl_scp.scp_cmdlen);
469779697Snon	cb->ccb_scsi_cmd[slp->sl_scp.scp_cmdlen - 1] |= 1;
469879697Snon	slp->sl_scp.scp_cmd = cb->ccb_scsi_cmd;
469979697Snon}
470079697Snon#endif	/* SCSI_LOW_DEBUG */
470179697Snon
470279697Snon/* static */ void
470367468Snonscsi_low_info(slp, ti, s)
470467468Snon	struct scsi_low_softc *slp;
470567468Snon	struct targ_info *ti;
470667468Snon	u_char *s;
470767468Snon{
470867468Snon
470979697Snon	if (slp == NULL)
471079697Snon		slp = LIST_FIRST(&sl_tab);
471179697Snon	if (s == NULL)
471279697Snon		s = "no message";
471379697Snon
471479697Snon	printf(">>>>> SCSI_LOW_INFO(0x%lx): %s\n", (u_long) slp->sl_Tnexus, s);
471567468Snon	if (ti == NULL)
471667468Snon	{
471779697Snon		for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
471879697Snon		     ti = TAILQ_NEXT(ti, ti_chain))
471979697Snon		{
472067468Snon			scsi_low_print(slp, ti);
472179697Snon		}
472267468Snon	}
472367468Snon	else
472479697Snon	{
472567468Snon		scsi_low_print(slp, ti);
472679697Snon	}
472767468Snon}
472867468Snon
472967468Snonstatic u_char *phase[] =
473067468Snon{
473167468Snon	"FREE", "ARBSTART", "SELSTART", "SELECTED",
473267468Snon	"CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL"
473367468Snon};
473467468Snon
473567468Snonvoid
473667468Snonscsi_low_print(slp, ti)
473767468Snon	struct scsi_low_softc *slp;
473867468Snon	struct targ_info *ti;
473967468Snon{
474079697Snon	struct lun_info *li;
474179697Snon	struct slccb *cb;
474279697Snon	struct sc_p *sp;
474367468Snon
474479697Snon	if (ti == NULL || ti == slp->sl_Tnexus)
474579697Snon	{
474679697Snon		ti = slp->sl_Tnexus;
474779697Snon		li = slp->sl_Lnexus;
474879697Snon		cb = slp->sl_Qnexus;
474979697Snon	}
475079697Snon	else
475179697Snon	{
475279697Snon		li = LIST_FIRST(&ti->ti_litab);
475379697Snon		cb = TAILQ_FIRST(&li->li_discq);
475479697Snon	}
475579697Snon 	sp = &slp->sl_scp;
475667468Snon
475779697Snon	printf("%s: === NEXUS T(0x%lx) L(0x%lx) Q(0x%lx) NIO(%d) ===\n",
475879697Snon		slp->sl_xname, (u_long) ti, (u_long) li, (u_long) cb,
475979697Snon		slp->sl_nio);
476067468Snon
476167468Snon	/* target stat */
476267468Snon	if (ti != NULL)
476367468Snon	{
476479697Snon		u_int flags = 0, maxnqio = 0, nqio = 0;
4765265633Smav		int lun = CAM_LUN_WILDCARD;
476667468Snon
476767468Snon		if (li != NULL)
476867468Snon		{
476967468Snon			lun = li->li_lun;
477067468Snon			flags = li->li_flags;
477179697Snon			maxnqio = li->li_maxnqio;
477279697Snon			nqio = li->li_nqio;
477367468Snon		}
477467468Snon
477579697Snon		printf("%s(%d:%d) ph<%s> => ph<%s> DISC(%d) QIO(%d:%d)\n",
477679697Snon			slp->sl_xname,
477767468Snon		       ti->ti_id, lun, phase[(int) ti->ti_ophase],
477879697Snon		       phase[(int) ti->ti_phase], ti->ti_disc,
477979697Snon		       nqio, maxnqio);
478067468Snon
478179697Snon		if (cb != NULL)
478279697Snon		{
478379697Snonprintf("CCB: cmd[0] 0x%x clen 0x%x dlen 0x%x<0x%x stat 0x%x err %b\n",
478479697Snon		       (u_int) cb->ccb_scp.scp_cmd[0],
478579697Snon		       cb->ccb_scp.scp_cmdlen,
478679697Snon		       cb->ccb_datalen,
478779697Snon		       cb->ccb_scp.scp_datalen,
478879697Snon		       (u_int) cb->ccb_sscp.scp_status,
478979697Snon		       cb->ccb_error, SCSI_LOW_ERRORBITS);
479079697Snon		}
479167468Snon
479279697Snonprintf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] attention: %d\n",
479379697Snon	       (u_int) (ti->ti_msginptr),
479479697Snon	       (u_int) (ti->ti_msgin[0]),
479579697Snon	       (u_int) (ti->ti_msgin[1]),
479679697Snon	       (u_int) (ti->ti_msgin[2]),
479779697Snon	       (u_int) (ti->ti_msgin[3]),
479879697Snon	       (u_int) (ti->ti_msgin[4]),
479979697Snon	       slp->sl_atten);
480079697Snon
480167468Snonprintf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n",
480279697Snon		(u_int) ti->ti_msgflags,
480379697Snon		(u_int) (ti->ti_msgoutstr[0]),
480479697Snon		(u_int) (ti->ti_msgoutstr[1]),
480579697Snon		(u_int) (ti->ti_msgoutstr[2]),
480679697Snon		(u_int) (ti->ti_msgoutstr[3]),
480779697Snon		(u_int) (ti->ti_msgoutstr[4]),
480879697Snon		ti->ti_msgoutlen,
480979697Snon		flags, SCSI_LOW_BITS);
481067468Snon
481179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
481279697Snon		scsi_low_msg_log_show(&ti->ti_log_msgin, "MIN LOG ", 2);
481379697Snon		scsi_low_msg_log_show(&ti->ti_log_msgout, "MOUT LOG", 2);
481479697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
481567468Snon
481667468Snon	}
481779697Snon
481879697Snon	printf("SCB: daddr 0x%lx dlen 0x%x stat 0x%x err %b\n",
481979697Snon	       (u_long) sp->scp_data,
482079697Snon	       sp->scp_datalen,
482179697Snon	       (u_int) sp->scp_status,
482279697Snon	       slp->sl_error, SCSI_LOW_ERRORBITS);
482367468Snon}
4824