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: releng/11.0/sys/cam/scsi/scsi_low.c 274760 2014-11-20 20:50:05Z jhb $");
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
1779697Snon#define	SCSI_LOW_FLAGS_QUIRKS_OK
1879697Snon
19139743Simp/*-
2067468Snon * [NetBSD for NEC PC-98 series]
2179697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
2267468Snon *	NetBSD/pc98 porting staff. All rights reserved.
2379697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
2467468Snon *	Naofumi HONDA. All rights reserved.
2579697Snon *
2679697Snon * [Ported for FreeBSD CAM]
2779697Snon *  Copyright (c) 2000, 2001
2879697Snon *      MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro.
2979697Snon *      All rights reserved.
3067468Snon *
3167468Snon *  Redistribution and use in source and binary forms, with or without
3267468Snon *  modification, are permitted provided that the following conditions
3367468Snon *  are met:
3467468Snon *  1. Redistributions of source code must retain the above copyright
3567468Snon *     notice, this list of conditions and the following disclaimer.
3667468Snon *  2. Redistributions in binary form must reproduce the above copyright
3767468Snon *     notice, this list of conditions and the following disclaimer in the
3867468Snon *     documentation and/or other materials provided with the distribution.
3967468Snon *  3. The name of the author may not be used to endorse or promote products
4067468Snon *     derived from this software without specific prior written permission.
4167468Snon *
4267468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4367468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
4467468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
4567468Snon * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
4667468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
4767468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
4867468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4967468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
5067468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
5167468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
5267468Snon * POSSIBILITY OF SUCH DAMAGE.
5367468Snon */
5467468Snon
5567468Snon/* <On the nexus establishment>
5667468Snon * When our host is reselected,
5767468Snon * nexus establish processes are little complicated.
5867468Snon * Normal steps are followings:
5979697Snon * 1) Our host selected by target => target nexus (slp->sl_Tnexus)
6079697Snon * 2) Identify msgin => lun nexus (slp->sl_Lnexus)
6179697Snon * 3) Qtag msg => ccb nexus (slp->sl_Qnexus)
6267468Snon */
6367468Snon#include "opt_ddb.h"
6467468Snon
6567468Snon#include <sys/param.h>
6667468Snon#include <sys/systm.h>
6767468Snon#include <sys/kernel.h>
6867468Snon#include <sys/bio.h>
6967468Snon#include <sys/buf.h>
7067468Snon#include <sys/queue.h>
7167468Snon#include <sys/malloc.h>
7267468Snon#include <sys/errno.h>
7367468Snon
7467468Snon#include <cam/cam.h>
7567468Snon#include <cam/cam_ccb.h>
7667468Snon#include <cam/cam_sim.h>
7767468Snon#include <cam/cam_debug.h>
7867468Snon#include <cam/cam_periph.h>
79147723Savatar#include <cam/cam_xpt_periph.h>
8067468Snon
8167468Snon#include <cam/scsi/scsi_all.h>
8273025Snon#include <cam/scsi/scsi_message.h>
8367468Snon
8467468Snon#include <cam/scsi/scsi_low.h>
8567468Snon
8667468Snon#include <sys/cons.h>
8767468Snon
8879697Snon/**************************************************************
8979697Snon * Constants
9079697Snon **************************************************************/
9179697Snon#define	SCSI_LOW_POLL_HZ	1000
9267468Snon
9379697Snon/* functions return values */
9479697Snon#define	SCSI_LOW_START_NO_QTAG	0
9579697Snon#define	SCSI_LOW_START_QTAG	1
9679697Snon
9767468Snon#define	SCSI_LOW_DONE_COMPLETE	0
9867468Snon#define	SCSI_LOW_DONE_RETRY	1
9967468Snon
10079697Snon/* internal disk flags */
10179697Snon#define	SCSI_LOW_DISK_DISC	0x00000001
10279697Snon#define	SCSI_LOW_DISK_QTAG	0x00000002
10379697Snon#define	SCSI_LOW_DISK_LINK	0x00000004
10479697Snon#define	SCSI_LOW_DISK_PARITY	0x00000008
10579697Snon#define	SCSI_LOW_DISK_SYNC	0x00010000
10679697Snon#define	SCSI_LOW_DISK_WIDE_16	0x00020000
10779697Snon#define	SCSI_LOW_DISK_WIDE_32	0x00040000
10879697Snon#define	SCSI_LOW_DISK_WIDE	(SCSI_LOW_DISK_WIDE_16 | SCSI_LOW_DISK_WIDE_32)
10979697Snon#define	SCSI_LOW_DISK_LFLAGS	0x0000ffff
11079697Snon#define	SCSI_LOW_DISK_TFLAGS	0xffff0000
11179697Snon
112227293Sedstatic MALLOC_DEFINE(M_SCSILOW, "SCSI low", "SCSI low buffers");
113147723Savatar
11479697Snon/**************************************************************
11579697Snon * Declarations
11679697Snon **************************************************************/
11792770Salfred/* static */ void scsi_low_info(struct scsi_low_softc *, struct targ_info *, u_char *);
11892770Salfredstatic void scsi_low_engage(void *);
11992770Salfredstatic struct slccb *scsi_low_establish_ccb(struct targ_info *, struct lun_info *, scsi_low_tag_t);
12092770Salfredstatic int scsi_low_done(struct scsi_low_softc *, struct slccb *);
12192770Salfredstatic int scsi_low_setup_done(struct scsi_low_softc *, struct slccb *);
12292770Salfredstatic void scsi_low_bus_release(struct scsi_low_softc *, struct targ_info *);
12392770Salfredstatic void scsi_low_twiddle_wait(void);
12492770Salfredstatic struct lun_info *scsi_low_alloc_li(struct targ_info *, int, int);
12592770Salfredstatic struct targ_info *scsi_low_alloc_ti(struct scsi_low_softc *, int);
12692770Salfredstatic void scsi_low_calcf_lun(struct lun_info *);
12792770Salfredstatic void scsi_low_calcf_target(struct targ_info *);
12892770Salfredstatic void scsi_low_calcf_show(struct lun_info *);
12992770Salfredstatic void scsi_low_reset_nexus(struct scsi_low_softc *, int);
13092770Salfredstatic void scsi_low_reset_nexus_target(struct scsi_low_softc *, struct targ_info *, int);
13192770Salfredstatic void scsi_low_reset_nexus_lun(struct scsi_low_softc *, struct lun_info *, int);
13292770Salfredstatic int scsi_low_init(struct scsi_low_softc *, u_int);
13392770Salfredstatic void scsi_low_start(struct scsi_low_softc *);
13492770Salfredstatic void scsi_low_free_ti(struct scsi_low_softc *);
13567468Snon
13692770Salfredstatic int scsi_low_alloc_qtag(struct slccb *);
13792770Salfredstatic int scsi_low_dealloc_qtag(struct slccb *);
13892770Salfredstatic int scsi_low_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *, u_int, u_int);
13992770Salfredstatic int scsi_low_message_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, u_int);
14092770Salfredstatic void scsi_low_unit_ready_cmd(struct slccb *);
14192770Salfredstatic void scsi_low_timeout(void *);
14292770Salfredstatic int scsi_low_timeout_check(struct scsi_low_softc *);
14379697Snon#ifdef	SCSI_LOW_START_UP_CHECK
14492770Salfredstatic int scsi_low_start_up(struct scsi_low_softc *);
14579697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
14692770Salfredstatic int scsi_low_abort_ccb(struct scsi_low_softc *, struct slccb *);
14792770Salfredstatic struct slccb *scsi_low_revoke_ccb(struct scsi_low_softc *, struct slccb *, int);
14879697Snon
14979697Snonint scsi_low_version_major = 2;
15079697Snonint scsi_low_version_minor = 17;
15179697Snon
15279697Snonstatic struct scsi_low_softc_tab sl_tab = LIST_HEAD_INITIALIZER(sl_tab);
153274760Sjhbstatic struct mtx sl_tab_lock;
154274760SjhbMTX_SYSINIT(sl_tab_lock, &sl_tab_lock, "scsi low table", MTX_DEF);
15579697Snon
15679697Snon/**************************************************************
15779697Snon * Debug, Run test and Statics
15879697Snon **************************************************************/
15979697Snon#ifdef	SCSI_LOW_INFO_DETAIL
16079697Snon#define	SCSI_LOW_INFO(slp, ti, s) scsi_low_info((slp), (ti), (s))
16179697Snon#else	/* !SCSI_LOW_INFO_DETAIL */
162240325Sjhb#define	SCSI_LOW_INFO(slp, ti, s) device_printf((slp)->sl_dev, "%s\n", (s))
16379697Snon#endif	/* !SCSI_LOW_INFO_DETAIL */
16479697Snon
16567468Snon#ifdef	SCSI_LOW_STATICS
16689113Smsmithstatic struct scsi_low_statics {
16767468Snon	int nexus_win;
16867468Snon	int nexus_fail;
16967468Snon	int nexus_disconnected;
17067468Snon	int nexus_reselected;
17167468Snon	int nexus_conflict;
17267468Snon} scsi_low_statics;
17367468Snon#endif	/* SCSI_LOW_STATICS */
17479697Snon
17579697Snon#ifdef	SCSI_LOW_DEBUG
17679697Snon#define	SCSI_LOW_DEBUG_DONE	0x00001
17779697Snon#define	SCSI_LOW_DEBUG_DISC	0x00002
17879697Snon#define	SCSI_LOW_DEBUG_SENSE	0x00004
17979697Snon#define	SCSI_LOW_DEBUG_CALCF	0x00008
18079697Snon#define	SCSI_LOW_DEBUG_ACTION	0x10000
18179697Snonint scsi_low_debug = 0;
18279697Snon
18379697Snon#define	SCSI_LOW_MAX_ATTEN_CHECK	32
18479697Snon#define	SCSI_LOW_ATTEN_CHECK	0x0001
18579697Snon#define	SCSI_LOW_CMDLNK_CHECK	0x0002
18679697Snon#define	SCSI_LOW_ABORT_CHECK	0x0004
18779697Snon#define	SCSI_LOW_NEXUS_CHECK	0x0008
18879697Snonint scsi_low_test = 0;
18979697Snonint scsi_low_test_id = 0;
19079697Snon
19192770Salfredstatic void scsi_low_test_abort(struct scsi_low_softc *, struct targ_info *, struct lun_info *);
19292770Salfredstatic void scsi_low_test_cmdlnk(struct scsi_low_softc *, struct slccb *);
19392770Salfredstatic void scsi_low_test_atten(struct scsi_low_softc *, struct targ_info *, u_int);
19479697Snon#define	SCSI_LOW_DEBUG_TEST_GO(fl, id) \
19579697Snon	((scsi_low_test & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
19679697Snon#define	SCSI_LOW_DEBUG_GO(fl, id) \
19779697Snon	((scsi_low_debug & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
19879697Snon#endif	/* SCSI_LOW_DEBUG */
19979697Snon
20067468Snon/**************************************************************
20179697Snon * CCB
20279697Snon **************************************************************/
20379697SnonGENERIC_CCB_STATIC_ALLOC(scsi_low, slccb)
20479697SnonGENERIC_CCB(scsi_low, slccb, ccb_chain)
20579697Snon
20679697Snon/**************************************************************
20779697Snon * Inline functions
20879697Snon **************************************************************/
20979697Snon#define	SCSI_LOW_INLINE	static __inline
21092770SalfredSCSI_LOW_INLINE void scsi_low_activate_qtag(struct slccb *);
21192770SalfredSCSI_LOW_INLINE void scsi_low_deactivate_qtag(struct slccb *);
21292770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_assert(struct slccb *, u_int);
21392770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_exec(struct scsi_low_softc *, struct slccb *);
21492770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_retry(struct slccb *);
21592770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_clear(struct slccb *);
21692770SalfredSCSI_LOW_INLINE void scsi_low_init_msgsys(struct scsi_low_softc *, struct targ_info *);
21779697Snon
21879697SnonSCSI_LOW_INLINE void
21979697Snonscsi_low_activate_qtag(cb)
22079697Snon	struct slccb *cb;
22179697Snon{
22279697Snon	struct lun_info *li = cb->li;
22379697Snon
22479697Snon	if (cb->ccb_tag != SCSI_LOW_UNKTAG)
22579697Snon		return;
22679697Snon
22779697Snon	li->li_nqio ++;
22879697Snon	cb->ccb_tag = cb->ccb_otag;
22979697Snon}
23079697Snon
23179697SnonSCSI_LOW_INLINE void
23279697Snonscsi_low_deactivate_qtag(cb)
23379697Snon	struct slccb *cb;
23479697Snon{
23579697Snon	struct lun_info *li = cb->li;
23679697Snon
23779697Snon	if (cb->ccb_tag == SCSI_LOW_UNKTAG)
23879697Snon		return;
23979697Snon
24079697Snon	li->li_nqio --;
24179697Snon	cb->ccb_tag = SCSI_LOW_UNKTAG;
24279697Snon}
24379697Snon
24479697SnonSCSI_LOW_INLINE void
24579697Snonscsi_low_ccb_message_exec(slp, cb)
24679697Snon	struct scsi_low_softc *slp;
24779697Snon	struct slccb *cb;
24879697Snon{
24979697Snon
25079697Snon	scsi_low_assert_msg(slp, cb->ti, cb->ccb_msgoutflag, 0);
25179697Snon	cb->ccb_msgoutflag = 0;
25279697Snon}
25379697Snon
25479697SnonSCSI_LOW_INLINE void
25579697Snonscsi_low_ccb_message_assert(cb, msg)
25679697Snon	struct slccb *cb;
25779697Snon	u_int msg;
25879697Snon{
25979697Snon
26079697Snon	cb->ccb_msgoutflag = cb->ccb_omsgoutflag = msg;
26179697Snon}
26279697Snon
26379697SnonSCSI_LOW_INLINE void
26479697Snonscsi_low_ccb_message_retry(cb)
26579697Snon	struct slccb *cb;
26679697Snon{
26779697Snon	cb->ccb_msgoutflag = cb->ccb_omsgoutflag;
26879697Snon}
26979697Snon
27079697SnonSCSI_LOW_INLINE void
27179697Snonscsi_low_ccb_message_clear(cb)
27279697Snon	struct slccb *cb;
27379697Snon{
27479697Snon	cb->ccb_msgoutflag = 0;
27579697Snon}
27679697Snon
27779697SnonSCSI_LOW_INLINE void
27879697Snonscsi_low_init_msgsys(slp, ti)
27979697Snon	struct scsi_low_softc *slp;
28079697Snon	struct targ_info *ti;
28179697Snon{
28279697Snon
28379697Snon	ti->ti_msginptr = 0;
28479697Snon	ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0;
28579697Snon	SCSI_LOW_DEASSERT_ATN(slp);
28679697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL);
28779697Snon}
28879697Snon
28979697Snon/*=============================================================
29079697Snon * START OF OS switch  (All OS depend fucntions should be here)
29179697Snon =============================================================*/
29279697Snon/* common os depend utitlities */
29379697Snon#define	SCSI_LOW_CMD_RESIDUAL_CHK	0x0001
29479697Snon#define	SCSI_LOW_CMD_ORDERED_QTAG	0x0002
29579697Snon#define	SCSI_LOW_CMD_ABORT_WARNING	0x0004
29679697Snon
29779697Snonstatic u_int8_t scsi_low_cmd_flags[256] = {
29879697Snon/*	0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
29979697Snon/*0*/	0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0,
30079697Snon/*1*/	0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
30179697Snon/*2*/	0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 5, 5,
30279697Snon/*3*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5,
30379697Snon};
30479697Snon
30579697Snonstruct scsi_low_error_code {
30679697Snon	int error_bits;
30779697Snon	int error_code;
30879697Snon};
30979697Snon
31092770Salfredstatic struct slccb *scsi_low_find_ccb(struct scsi_low_softc *, u_int, u_int, void *);
31192770Salfredstatic int scsi_low_translate_error_code(struct slccb *, struct scsi_low_error_code *);
31279697Snon
31379697Snonstatic struct slccb *
31479697Snonscsi_low_find_ccb(slp, target, lun, osdep)
31579697Snon	struct scsi_low_softc *slp;
31679697Snon	u_int target, lun;
31779697Snon	void *osdep;
31879697Snon{
31979697Snon	struct targ_info *ti;
32079697Snon	struct lun_info *li;
32179697Snon	struct slccb *cb;
32279697Snon
32379697Snon	ti = slp->sl_ti[target];
32479697Snon	li = scsi_low_alloc_li(ti, lun, 0);
32579697Snon	if (li == NULL)
32679697Snon		return NULL;
32779697Snon
32879697Snon	if ((cb = slp->sl_Qnexus) != NULL && cb->osdep == osdep)
32979697Snon		return cb;
33079697Snon
331270225Sjhb	TAILQ_FOREACH(cb, &slp->sl_start, ccb_chain)
33279697Snon	{
33379697Snon		if (cb->osdep == osdep)
33479697Snon			return cb;
33579697Snon	}
33679697Snon
337270225Sjhb	TAILQ_FOREACH(cb, &li->li_discq, ccb_chain)
33879697Snon	{
33979697Snon		if (cb->osdep == osdep)
34079697Snon			return cb;
34179697Snon	}
34279697Snon	return NULL;
34379697Snon}
34479697Snon
34579697Snonstatic int
34679697Snonscsi_low_translate_error_code(cb, tp)
34779697Snon	struct slccb *cb;
34879697Snon	struct scsi_low_error_code *tp;
34979697Snon{
35079697Snon
35179697Snon	if (cb->ccb_error == 0)
35279697Snon		return tp->error_code;
35379697Snon
35479697Snon	for (tp ++; (cb->ccb_error & tp->error_bits) == 0; tp ++)
35579697Snon		;
35679697Snon	return tp->error_code;
35779697Snon}
35879697Snon
35979697Snon/**************************************************************
36079697Snon * SCSI INTERFACE (CAM)
36179697Snon **************************************************************/
362147723Savatar#define	SCSI_LOW_MALLOC(size)		malloc((size), M_SCSILOW, M_NOWAIT)
363147723Savatar#define	SCSI_LOW_FREE(pt)		free((pt), M_SCSILOW)
36479697Snon#define	SCSI_LOW_ALLOC_CCB(flags)	scsi_low_get_ccb()
36579697Snon
36692770Salfredstatic void scsi_low_poll_cam(struct cam_sim *);
36792770Salfredvoid scsi_low_scsi_action_cam(struct cam_sim *, union ccb *);
36879697Snon
36992770Salfredstatic int scsi_low_attach_cam(struct scsi_low_softc *);
370274760Sjhbstatic int scsi_low_detach_cam(struct scsi_low_softc *);
37192770Salfredstatic int scsi_low_ccb_setup_cam(struct scsi_low_softc *, struct slccb *);
37292770Salfredstatic int scsi_low_done_cam(struct scsi_low_softc *, struct slccb *);
37379697Snon
37479697Snonstruct scsi_low_error_code scsi_low_error_code_cam[] = {
37579697Snon	{0,			CAM_REQ_CMP},
37679697Snon	{SENSEIO, 		CAM_AUTOSNS_VALID | CAM_REQ_CMP_ERR},
37779697Snon	{SENSEERR,		CAM_AUTOSENSE_FAIL},
37879697Snon	{UACAERR,		CAM_SCSI_STATUS_ERROR},
37979697Snon	{BUSYERR | STATERR,	CAM_SCSI_STATUS_ERROR},
38079697Snon	{SELTIMEOUTIO,		CAM_SEL_TIMEOUT},
38179697Snon	{TIMEOUTIO,		CAM_CMD_TIMEOUT},
38279697Snon	{PDMAERR,		CAM_DATA_RUN_ERR},
38379697Snon	{PARITYERR,		CAM_UNCOR_PARITY},
38479697Snon	{UBFERR,		CAM_UNEXP_BUSFREE},
38579697Snon	{ABORTIO,		CAM_REQ_ABORTED},
38679697Snon	{-1,			CAM_UNREC_HBA_ERROR}
38779697Snon};
38879697Snon
38979697Snon#define	SIM2SLP(sim)	((struct scsi_low_softc *) cam_sim_softc((sim)))
39079697Snon
39179697Snon/* XXX:
39279697Snon * Please check a polling hz, currently we assume scsi_low_poll() is
39379697Snon * called each 1 ms.
39479697Snon */
39579697Snon#define	SCSI_LOW_CAM_POLL_HZ	1000	/* OK ? */
39679697Snon
39779697Snonstatic void
39879697Snonscsi_low_poll_cam(sim)
39979697Snon	struct cam_sim *sim;
40079697Snon{
40179697Snon	struct scsi_low_softc *slp = SIM2SLP(sim);
40279697Snon
403274760Sjhb	SCSI_LOW_ASSERT_LOCKED(slp);
40479697Snon	(*slp->sl_funcs->scsi_low_poll) (slp);
40579697Snon
406274760Sjhb	if (slp->sl_poll_count ++ >=
40779697Snon	    SCSI_LOW_CAM_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
40879697Snon	{
409274760Sjhb		slp->sl_poll_count = 0;
41079697Snon		scsi_low_timeout_check(slp);
41179697Snon	}
41279697Snon}
41379697Snon
41479697Snonvoid
41579697Snonscsi_low_scsi_action_cam(sim, ccb)
41679697Snon	struct cam_sim *sim;
41779697Snon	union ccb *ccb;
41879697Snon{
41979697Snon	struct scsi_low_softc *slp = SIM2SLP(sim);
42079697Snon	struct targ_info *ti;
42179697Snon	struct lun_info *li;
42279697Snon	struct slccb *cb;
42379697Snon	u_int lun, flags, msg, target;
424274760Sjhb	int rv;
42579697Snon
426274760Sjhb	SCSI_LOW_ASSERT_LOCKED(slp);
42779697Snon	target = (u_int) (ccb->ccb_h.target_id);
42879697Snon	lun = (u_int) ccb->ccb_h.target_lun;
42979697Snon
43079697Snon#ifdef	SCSI_LOW_DEBUG
43179697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_ACTION, target) != 0)
43279697Snon	{
433240325Sjhb		device_printf(slp->sl_dev,
434240325Sjhb		    "cam_action: func code 0x%x target: %d, lun: %d\n",
435240325Sjhb		    ccb->ccb_h.func_code, target, lun);
43679697Snon	}
43779697Snon#endif	/* SCSI_LOW_DEBUG */
43879697Snon
43979697Snon	switch (ccb->ccb_h.func_code) {
44079697Snon	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
44179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
44279697Snon		if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
44379697Snon		{
444240325Sjhb			device_printf(slp->sl_dev, "invalid target/lun\n");
44579697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
44679697Snon			xpt_done(ccb);
44779697Snon			return;
44879697Snon		}
44979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
45079697Snon
45179697Snon		if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) {
45279697Snon			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
45379697Snon			xpt_done(ccb);
45479697Snon			return;
45579697Snon		}
45679697Snon
45779697Snon		ti = slp->sl_ti[target];
45879697Snon		cb->osdep = ccb;
45979697Snon		cb->bp = NULL;
46079697Snon		if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
46179697Snon			flags = CCB_AUTOSENSE | CCB_SCSIIO;
46279697Snon		else
46379697Snon			flags = CCB_SCSIIO;
46479697Snon
46579697Snon		li = scsi_low_alloc_li(ti, lun, 1);
46679697Snon
46779697Snon		if (ti->ti_setup_msg != 0)
46879697Snon		{
46979697Snon			scsi_low_message_enqueue(slp, ti, li, CCB_AUTOSENSE);
47079697Snon		}
47179697Snon
47279697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, 0);
47379697Snon
47479697Snon#ifdef	SCSI_LOW_DEBUG
47579697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, target) != 0)
47679697Snon		{
47779697Snon			scsi_low_test_abort(slp, ti, li);
47879697Snon		}
47979697Snon#endif	/* SCSI_LOW_DEBUG */
48079697Snon		break;
48179697Snon
48279697Snon	case XPT_EN_LUN:		/* Enable LUN as a target */
48379697Snon	case XPT_TARGET_IO:		/* Execute target I/O request */
48479697Snon	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
48579697Snon	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
48679697Snon		/* XXX Implement */
48779697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
48879697Snon		xpt_done(ccb);
48979697Snon		break;
49079697Snon
49179697Snon	case XPT_ABORT:			/* Abort the specified CCB */
49279697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
49379697Snon		if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
49479697Snon		{
495240325Sjhb			device_printf(slp->sl_dev, "invalid target/lun\n");
49679697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
49779697Snon			xpt_done(ccb);
49879697Snon			return;
49979697Snon		}
50079697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
50179697Snon
50279697Snon		cb = scsi_low_find_ccb(slp, target, lun, ccb->cab.abort_ccb);
50379697Snon		rv = scsi_low_abort_ccb(slp, cb);
50479697Snon
50579697Snon		if (rv == 0)
50679697Snon			ccb->ccb_h.status = CAM_REQ_CMP;
50779697Snon		else
50879697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
50979697Snon		xpt_done(ccb);
51079697Snon		break;
51179697Snon
51279697Snon	case XPT_SET_TRAN_SETTINGS: {
513163816Smjacob		struct ccb_trans_settings_scsi *scsi;
514163816Smjacob        	struct ccb_trans_settings_spi *spi;
51579697Snon		struct ccb_trans_settings *cts;
51679697Snon		u_int val;
51779697Snon
51879697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
51979697Snon		if (target == CAM_TARGET_WILDCARD)
52079697Snon		{
521240325Sjhb			device_printf(slp->sl_dev, "invalid target\n");
52279697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
52379697Snon			xpt_done(ccb);
52479697Snon			return;
52579697Snon		}
52679697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
52779697Snon		cts = &ccb->cts;
52879697Snon		ti = slp->sl_ti[target];
52979697Snon		if (lun == CAM_LUN_WILDCARD)
53079697Snon			lun = 0;
53179697Snon
532163816Smjacob		scsi = &cts->proto_specific.scsi;
533163816Smjacob		spi = &cts->xport_specific.spi;
534163816Smjacob		if ((spi->valid & (CTS_SPI_VALID_BUS_WIDTH |
535163816Smjacob				   CTS_SPI_VALID_SYNC_RATE |
536163816Smjacob				   CTS_SPI_VALID_SYNC_OFFSET)) != 0)
537163816Smjacob		{
538163816Smjacob			if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) {
539163816Smjacob				val = spi->bus_width;
540163816Smjacob				if (val < ti->ti_width)
541163816Smjacob					ti->ti_width = val;
542163816Smjacob			}
543163816Smjacob			if (spi->valid & CTS_SPI_VALID_SYNC_RATE) {
544163816Smjacob				val = spi->sync_period;
545163816Smjacob				if (val == 0 || val > ti->ti_maxsynch.period)
546163816Smjacob					ti->ti_maxsynch.period = val;
547163816Smjacob			}
548163816Smjacob			if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) {
549163816Smjacob				val = spi->sync_offset;
550163816Smjacob				if (val < ti->ti_maxsynch.offset)
551163816Smjacob					ti->ti_maxsynch.offset = val;
552163816Smjacob			}
553163816Smjacob			ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
554163816Smjacob			scsi_low_calcf_target(ti);
555163816Smjacob		}
556163816Smjacob
557163816Smjacob		if ((spi->valid & CTS_SPI_FLAGS_DISC_ENB) != 0 ||
558163816Smjacob                    (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
559163816Smjacob
560163816Smjacob			li = scsi_low_alloc_li(ti, lun, 1);
561163816Smjacob			if (spi->valid & CTS_SPI_FLAGS_DISC_ENB) {
562163816Smjacob				li->li_quirks |= SCSI_LOW_DISK_DISC;
563163816Smjacob			} else {
564163816Smjacob				li->li_quirks &= ~SCSI_LOW_DISK_DISC;
565163816Smjacob			}
566163816Smjacob
567163816Smjacob			if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) {
568163816Smjacob				li->li_quirks |= SCSI_LOW_DISK_QTAG;
569163816Smjacob			} else {
570163816Smjacob				li->li_quirks &= ~SCSI_LOW_DISK_QTAG;
571163816Smjacob			}
572163816Smjacob			li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
573163816Smjacob			scsi_low_calcf_target(ti);
574163816Smjacob			scsi_low_calcf_lun(li);
575163816Smjacob			if ((slp->sl_show_result & SHOW_CALCF_RES) != 0)
576163816Smjacob				scsi_low_calcf_show(li);
577163816Smjacob		}
57879697Snon
57979697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
58079697Snon		xpt_done(ccb);
58179697Snon		break;
58279697Snon	}
58379697Snon
58479697Snon	case XPT_GET_TRAN_SETTINGS: {
58579697Snon		struct ccb_trans_settings *cts;
58679697Snon		u_int diskflags;
58779697Snon
58879697Snon		cts = &ccb->cts;
58979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
59079697Snon		if (target == CAM_TARGET_WILDCARD)
59179697Snon		{
592240325Sjhb			device_printf(slp->sl_dev, "invalid target\n");
59379697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
59479697Snon			xpt_done(ccb);
59579697Snon			return;
59679697Snon		}
59779697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
59879697Snon		ti = slp->sl_ti[target];
59979697Snon		if (lun == CAM_LUN_WILDCARD)
60079697Snon			lun = 0;
60179697Snon
60279697Snon		li = scsi_low_alloc_li(ti, lun, 1);
60379697Snon		if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) {
60479697Snon			struct ccb_trans_settings_scsi *scsi =
60579697Snon				&cts->proto_specific.scsi;
60679697Snon			struct ccb_trans_settings_spi *spi =
60779697Snon				&cts->xport_specific.spi;
60879697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
60979697Snon			if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID)
61079697Snon			{
61179697Snon				ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
612240325Sjhb				device_printf(slp->sl_dev,
613240325Sjhb				    "invalid GET_TRANS_CURRENT_SETTINGS call\n");
61479697Snon				goto settings_out;
61579697Snon			}
61679697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
61779697Snon			cts->protocol = PROTO_SCSI;
61879697Snon			cts->protocol_version = SCSI_REV_2;
61979697Snon			cts->transport = XPORT_SPI;
62079697Snon			cts->transport_version = 2;
62179697Snon
62279697Snon			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
62379697Snon			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
62479697Snon
62579697Snon			diskflags = li->li_diskflags & li->li_cfgflags;
62679697Snon			if (diskflags & SCSI_LOW_DISK_DISC)
62779697Snon				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
62879697Snon			if (diskflags & SCSI_LOW_DISK_QTAG)
62979697Snon				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
63079697Snon
63179697Snon			spi->sync_period = ti->ti_maxsynch.period;
63279697Snon			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
63379697Snon			spi->sync_offset = ti->ti_maxsynch.offset;
63479697Snon			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
63579697Snon
63679697Snon			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
63779697Snon			spi->bus_width = ti->ti_width;
63879697Snon
63979697Snon			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
64079697Snon				scsi->valid = CTS_SCSI_VALID_TQ;
64179697Snon				spi->valid |= CTS_SPI_VALID_DISC;
64279697Snon			} else
64379697Snon				scsi->valid = 0;
64479697Snon		} else
64579697Snon			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
64679697Snonsettings_out:
64779697Snon		xpt_done(ccb);
64879697Snon		break;
64979697Snon	}
65079697Snon
65179697Snon	case XPT_CALC_GEOMETRY: { /* not yet HN2 */
652116351Snjl		cam_calc_geometry(&ccb->ccg, /*extended*/1);
65379697Snon		xpt_done(ccb);
65479697Snon		break;
65579697Snon	}
65679697Snon
65779697Snon	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
65879697Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL);
65979697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
66079697Snon		xpt_done(ccb);
66179697Snon		break;
66279697Snon
66379697Snon	case XPT_TERM_IO:	/* Terminate the I/O process */
66479697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
66579697Snon		xpt_done(ccb);
66679697Snon		break;
66779697Snon
66879697Snon	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
66979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
67079697Snon		if (target == CAM_TARGET_WILDCARD)
67179697Snon		{
672240325Sjhb			device_printf(slp->sl_dev, "invalid target\n");
67379697Snon			ccb->ccb_h.status = CAM_REQ_INVALID;
67479697Snon			xpt_done(ccb);
67579697Snon			return;
67679697Snon		}
67779697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
67879697Snon
67979697Snon		msg = SCSI_LOW_MSG_RESET;
68079697Snon		if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL))
68179697Snon		{
68279697Snon			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
68379697Snon			xpt_done(ccb);
68479697Snon			return;
68579697Snon		}
68679697Snon
68779697Snon		ti = slp->sl_ti[target];
68879697Snon		if (lun == CAM_LUN_WILDCARD)
68979697Snon			lun = 0;
69079697Snon		cb->osdep = ccb;
69179697Snon		cb->bp = NULL;
69279697Snon		if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
69379697Snon			flags = CCB_AUTOSENSE | CCB_NORETRY | CCB_URGENT;
69479697Snon		else
69579697Snon			flags = CCB_NORETRY | CCB_URGENT;
69679697Snon
69779697Snon		li = scsi_low_alloc_li(ti, lun, 1);
69879697Snon		scsi_low_enqueue(slp, ti, li, cb, flags, msg);
69979697Snon		break;
70079697Snon
70179697Snon	case XPT_PATH_INQ: {		/* Path routing inquiry */
70279697Snon		struct ccb_pathinq *cpi = &ccb->cpi;
70379697Snon
70479697Snon		cpi->version_num = scsi_low_version_major;
70579697Snon		cpi->hba_inquiry = PI_TAG_ABLE | PI_LINKED_CDB;
70679697Snon		ti = slp->sl_ti[slp->sl_hostid];	/* host id */
70779697Snon		if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
70879697Snon			cpi->hba_inquiry |= PI_WIDE_16;
70979697Snon		if (ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
71079697Snon			cpi->hba_inquiry |= PI_WIDE_32;
71179697Snon		if (ti->ti_maxsynch.offset > 0)
71279697Snon			cpi->hba_inquiry |= PI_SDTR_ABLE;
71379697Snon		cpi->target_sprt = 0;
71479697Snon		cpi->hba_misc = 0;
71579697Snon		cpi->hba_eng_cnt = 0;
71679697Snon		cpi->max_target = slp->sl_ntargs - 1;
71779697Snon		cpi->max_lun = slp->sl_nluns - 1;
71879697Snon		cpi->initiator_id = slp->sl_hostid;
71979697Snon		cpi->bus_id = cam_sim_bus(sim);
72079697Snon		cpi->base_transfer_speed = 3300;
72179697Snon		cpi->transport = XPORT_SPI;
72279697Snon		cpi->transport_version = 2;
72379697Snon		cpi->protocol = PROTO_SCSI;
72479697Snon		cpi->protocol_version = SCSI_REV_2;
72579697Snon		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
72679697Snon		strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN);
72779697Snon		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
72879697Snon		cpi->unit_number = cam_sim_unit(sim);
72979697Snon		cpi->ccb_h.status = CAM_REQ_CMP;
73079697Snon		xpt_done(ccb);
73179697Snon		break;
73279697Snon	}
73379697Snon
73479697Snon	default:
73579697Snon	        printf("scsi_low: non support func_code = %d ",
73679697Snon			ccb->ccb_h.func_code);
73779697Snon		ccb->ccb_h.status = CAM_REQ_INVALID;
73879697Snon		xpt_done(ccb);
73979697Snon		break;
74079697Snon	}
74179697Snon}
74279697Snon
74379697Snonstatic int
74479697Snonscsi_low_attach_cam(slp)
74579697Snon	struct scsi_low_softc *slp;
74679697Snon{
74779697Snon	struct cam_devq *devq;
74879697Snon	int tagged_openings;
74979697Snon
75079697Snon	devq = cam_simq_alloc(SCSI_LOW_NCCB);
75179697Snon	if (devq == NULL)
75279697Snon		return (ENOMEM);
75379697Snon
75479697Snon	/*
75579697Snon	 * ask the adapter what subunits are present
75679697Snon	 */
75779697Snon	tagged_openings = min(slp->sl_openings, SCSI_LOW_MAXNEXUS);
758274760Sjhb	slp->sl_sim = cam_sim_alloc(scsi_low_scsi_action_cam,
75979697Snon				scsi_low_poll_cam,
760240172Sjhb				device_get_name(slp->sl_dev), slp,
761274760Sjhb				device_get_unit(slp->sl_dev), &slp->sl_lock,
76279697Snon				slp->sl_openings, tagged_openings, devq);
76379697Snon
764274760Sjhb	if (slp->sl_sim == NULL) {
76579697Snon		cam_simq_free(devq);
76679697Snon	 	return ENODEV;
76779697Snon	}
76879697Snon
769274760Sjhb	SCSI_LOW_LOCK(slp);
770274760Sjhb	if (xpt_bus_register(slp->sl_sim, slp->sl_dev, 0) != CAM_SUCCESS) {
771274760Sjhb		cam_sim_free(slp->sl_sim, TRUE);
772274760Sjhb		SCSI_LOW_UNLOCK(slp);
77379697Snon	 	return ENODEV;
77479697Snon	}
77579697Snon
776274760Sjhb	if (xpt_create_path(&slp->sl_path, /*periph*/NULL,
777274760Sjhb			cam_sim_path(slp->sl_sim), CAM_TARGET_WILDCARD,
77879697Snon			CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
779274760Sjhb		xpt_bus_deregister(cam_sim_path(slp->sl_sim));
780274760Sjhb		cam_sim_free(slp->sl_sim, /*free_simq*/TRUE);
781274760Sjhb		SCSI_LOW_UNLOCK(slp);
78279697Snon		return ENODEV;
78379697Snon	}
78479697Snon
78579697Snon	slp->sl_show_result = SHOW_CALCF_RES;		/* OK ? */
786274760Sjhb	SCSI_LOW_UNLOCK(slp);
78779697Snon	return 0;
78879697Snon}
78979697Snon
79079697Snonstatic int
791274760Sjhbscsi_low_detach_cam(slp)
79279697Snon	struct scsi_low_softc *slp;
79379697Snon{
79479697Snon
795274760Sjhb	xpt_async(AC_LOST_DEVICE, slp->sl_path, NULL);
796274760Sjhb	xpt_free_path(slp->sl_path);
797274760Sjhb	xpt_bus_deregister(cam_sim_path(slp->sl_sim));
798274760Sjhb	cam_sim_free(slp->sl_sim, /* free_devq */ TRUE);
79979697Snon	return 0;
80079697Snon}
80179697Snon
80279697Snonstatic int
80379697Snonscsi_low_ccb_setup_cam(slp, cb)
80479697Snon	struct scsi_low_softc *slp;
80579697Snon	struct slccb *cb;
80679697Snon{
80779697Snon        union ccb *ccb = (union ccb *) cb->osdep;
80879697Snon
80979697Snon	if ((cb->ccb_flags & CCB_SCSIIO) != 0)
81079697Snon	{
81179697Snon		cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes;
81279697Snon		cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len;
81379697Snon		cb->ccb_scp.scp_data = ccb->csio.data_ptr;
81479697Snon		cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len;
81579697Snon		if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
81679697Snon			cb->ccb_scp.scp_direction = SCSI_LOW_WRITE;
81779697Snon		else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */
81879697Snon			cb->ccb_scp.scp_direction = SCSI_LOW_READ;
81979697Snon		cb->ccb_tcmax = ccb->ccb_h.timeout / 1000;
82079697Snon	}
82179697Snon	else
82279697Snon	{
82379697Snon		scsi_low_unit_ready_cmd(cb);
82479697Snon	}
82579697Snon	return SCSI_LOW_START_QTAG;
82679697Snon}
82779697Snon
82879697Snonstatic int
82979697Snonscsi_low_done_cam(slp, cb)
83079697Snon	struct scsi_low_softc *slp;
83179697Snon	struct slccb *cb;
83279697Snon{
83379697Snon	union ccb *ccb;
83479697Snon
83579697Snon	ccb = (union ccb *) cb->osdep;
83679697Snon	if (cb->ccb_error == 0)
83779697Snon	{
83879697Snon		ccb->ccb_h.status = CAM_REQ_CMP;
83979697Snon		ccb->csio.resid = 0;
84079697Snon	}
84179697Snon	else
84279697Snon	{
84379697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
84479697Snon			cb->ccb_error |= ABORTIO;
84579697Snon
84679697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
84779697Snon		    (cb->ccb_error & ABORTIO) == 0)
84879697Snon			return EJUSTRETURN;
84979697Snon
85079697Snon		if ((cb->ccb_error & SENSEIO) != 0)
85179697Snon		{
85279697Snon			memcpy(&ccb->csio.sense_data,
85379697Snon			       &cb->ccb_sense,
85479697Snon			       sizeof(ccb->csio.sense_data));
85579697Snon		}
85679697Snon
85779697Snon		ccb->ccb_h.status = scsi_low_translate_error_code(cb,
85879697Snon					&scsi_low_error_code_cam[0]);
85979697Snon
86079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
86179697Snon		if ((cb->ccb_flags & CCB_SILENT) == 0 &&
86279697Snon		    cb->ccb_scp.scp_cmdlen > 0 &&
86379697Snon		    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
86479697Snon		     SCSI_LOW_CMD_ABORT_WARNING) != 0)
86579697Snon		{
866240325Sjhb			device_printf(slp->sl_dev,
867240325Sjhb			    "WARNING: scsi_low IO abort\n");
86879697Snon			scsi_low_print(slp, NULL);
86979697Snon		}
87079697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
87179697Snon	}
87279697Snon
87379697Snon	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0)
87479697Snon		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
87579697Snon
87679697Snon	if (cb->ccb_scp.scp_status == ST_UNKNOWN)
87779697Snon		ccb->csio.scsi_status = 0;	/* XXX */
87879697Snon	else
87979697Snon		ccb->csio.scsi_status = cb->ccb_scp.scp_status;
88079697Snon
88179697Snon	if ((cb->ccb_flags & CCB_NOSDONE) == 0)
88279697Snon		xpt_done(ccb);
88379697Snon	return 0;
88479697Snon}
88579697Snon
88679697Snon/**************************************************************
88779697Snon * scsi low deactivate and activate
88879697Snon **************************************************************/
88979697Snonint
89079697Snonscsi_low_is_busy(slp)
89179697Snon	struct scsi_low_softc *slp;
89279697Snon{
89379697Snon
89479697Snon	if (slp->sl_nio > 0)
89579697Snon		return EBUSY;
89679697Snon	return 0;
89779697Snon}
89879697Snon
89979697Snonint
90079697Snonscsi_low_deactivate(slp)
90179697Snon	struct scsi_low_softc *slp;
90279697Snon{
90379697Snon
90479697Snon	slp->sl_flags |= HW_INACTIVE;
905274760Sjhb	callout_stop(&slp->sl_timeout_timer);
906274760Sjhb	callout_stop(&slp->sl_engage_timer);
90779697Snon	return 0;
90879697Snon}
90979697Snon
91079697Snonint
91179697Snonscsi_low_activate(slp)
91279697Snon	struct scsi_low_softc *slp;
91379697Snon{
914274760Sjhb	int error;
91579697Snon
91679697Snon	slp->sl_flags &= ~HW_INACTIVE;
91779697Snon	if ((error = scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL)) != 0)
91879697Snon	{
91979697Snon		slp->sl_flags |= HW_INACTIVE;
92079697Snon		return error;
92179697Snon	}
92279697Snon
92379697Snon	slp->sl_timeout_count = 0;
924274760Sjhb	callout_reset(&slp->sl_timeout_timer, hz / SCSI_LOW_TIMEOUT_HZ,
925274760Sjhb	    scsi_low_timeout, slp);
92679697Snon	return 0;
92779697Snon}
92879697Snon
92979697Snon/**************************************************************
93079697Snon * scsi low log
93179697Snon **************************************************************/
93279697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
93392770Salfredstatic void scsi_low_msg_log_init(struct scsi_low_msg_log *);
93492770Salfredstatic void scsi_low_msg_log_write(struct scsi_low_msg_log *, u_int8_t *, int);
93592770Salfredstatic void scsi_low_msg_log_show(struct scsi_low_msg_log *, char *, int);
93679697Snon
93779697Snonstatic void
93879697Snonscsi_low_msg_log_init(slmlp)
93979697Snon	struct scsi_low_msg_log *slmlp;
94079697Snon{
94179697Snon
94279697Snon	slmlp->slml_ptr = 0;
94379697Snon}
94479697Snon
94579697Snonstatic void
94679697Snonscsi_low_msg_log_write(slmlp, datap, len)
94779697Snon	struct scsi_low_msg_log *slmlp;
94879697Snon	u_int8_t *datap;
94979697Snon	int len;
95079697Snon{
95179697Snon	int ptr, ind;
95279697Snon
95379697Snon	if (slmlp->slml_ptr >= SCSI_LOW_MSG_LOG_DATALEN)
95479697Snon		return;
95579697Snon
95679697Snon	ptr = slmlp->slml_ptr ++;
95779697Snon	for (ind = 0; ind < sizeof(slmlp->slml_msg[0]) && ind < len; ind ++)
95879697Snon		slmlp->slml_msg[ptr].msg[ind] = datap[ind];
95979697Snon	for ( ; ind < sizeof(slmlp->slml_msg[0]); ind ++)
96079697Snon		slmlp->slml_msg[ptr].msg[ind] = 0;
96179697Snon}
96279697Snon
96379697Snonstatic void
96479697Snonscsi_low_msg_log_show(slmlp, s, len)
96579697Snon	struct scsi_low_msg_log *slmlp;
96679697Snon	char *s;
96779697Snon	int len;
96879697Snon{
96979697Snon	int ptr, ind;
97079697Snon
97179697Snon	printf("%s: (%d) ", s, slmlp->slml_ptr);
97279697Snon	for (ptr = 0; ptr < slmlp->slml_ptr; ptr ++)
97379697Snon	{
97479697Snon		for (ind = 0; ind < len && ind < sizeof(slmlp->slml_msg[0]);
97579697Snon		     ind ++)
97679697Snon		{
97779697Snon			printf("[%x]", (u_int) slmlp->slml_msg[ptr].msg[ind]);
97879697Snon		}
97979697Snon		printf(">");
98079697Snon	}
98179697Snon	printf("\n");
98279697Snon}
98379697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
98479697Snon
98579697Snon/**************************************************************
98667468Snon * power control
98767468Snon **************************************************************/
98867468Snonstatic void
98967468Snonscsi_low_engage(arg)
99067468Snon	void *arg;
99167468Snon{
99267468Snon	struct scsi_low_softc *slp = arg;
99367468Snon
994274760Sjhb	SCSI_LOW_ASSERT_LOCKED(slp);
99567468Snon	switch (slp->sl_rstep)
99667468Snon	{
99767468Snon	case 0:
99867468Snon		slp->sl_rstep ++;
99967468Snon		(*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
1000274760Sjhb		callout_reset(&slp->sl_engage_timer, hz / 1000,
1001274760Sjhb		    scsi_low_engage, slp);
100267468Snon		break;
100367468Snon
100467468Snon	case 1:
100567468Snon		slp->sl_rstep ++;
100667468Snon		slp->sl_flags &= ~HW_RESUME;
100767468Snon		scsi_low_start(slp);
100867468Snon		break;
100967468Snon
101067468Snon	case 2:
101167468Snon		break;
101267468Snon	}
101367468Snon}
101467468Snon
101567468Snonstatic int
101667468Snonscsi_low_init(slp, flags)
101767468Snon	struct scsi_low_softc *slp;
101867468Snon	u_int flags;
101967468Snon{
102079697Snon	int rv = 0;
102167468Snon
102279697Snon	slp->sl_flags |= HW_INITIALIZING;
102379697Snon
102479697Snon	/* clear power control timeout */
102567468Snon	if ((slp->sl_flags & HW_POWERCTRL) != 0)
102667468Snon	{
1027274760Sjhb		callout_stop(&slp->sl_engage_timer);
102867468Snon		slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME);
102967468Snon		slp->sl_active = 1;
103067468Snon		slp->sl_powc = SCSI_LOW_POWDOWN_TC;
103167468Snon	}
103267468Snon
103367468Snon	/* reset current nexus */
103467468Snon	scsi_low_reset_nexus(slp, flags);
103567468Snon	if ((slp->sl_flags & HW_INACTIVE) != 0)
103679697Snon	{
103779697Snon		rv = EBUSY;
103879697Snon		goto out;
103979697Snon	}
104067468Snon
104179697Snon	if (flags != SCSI_LOW_RESTART_SOFT)
104279697Snon	{
104379697Snon		rv = ((*slp->sl_funcs->scsi_low_init) (slp, flags));
104479697Snon	}
104567468Snon
104679697Snonout:
104779697Snon	slp->sl_flags &= ~HW_INITIALIZING;
104879697Snon	return rv;
104967468Snon}
105067468Snon
105167468Snon/**************************************************************
105267468Snon * allocate lun_info
105367468Snon **************************************************************/
105467468Snonstatic struct lun_info *
105567468Snonscsi_low_alloc_li(ti, lun, alloc)
105667468Snon	struct targ_info *ti;
105767468Snon	int lun;
105867468Snon	int alloc;
105967468Snon{
106079697Snon	struct scsi_low_softc *slp = ti->ti_sc;
106167468Snon	struct lun_info *li;
106267468Snon
106367468Snon	li = LIST_FIRST(&ti->ti_litab);
106467468Snon	if (li != NULL)
106567468Snon	{
106667468Snon		if (li->li_lun == lun)
106767468Snon			return li;
106867468Snon
106967468Snon		while ((li = LIST_NEXT(li, lun_chain)) != NULL)
107067468Snon		{
107167468Snon			if (li->li_lun == lun)
107267468Snon			{
107367468Snon				LIST_REMOVE(li, lun_chain);
107467468Snon				LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain);
107567468Snon				return li;
107667468Snon			}
107767468Snon		}
107867468Snon	}
107967468Snon
108067468Snon	if (alloc == 0)
108167468Snon		return li;
108267468Snon
108379697Snon	li = SCSI_LOW_MALLOC(ti->ti_lunsize);
108467468Snon	if (li == NULL)
1085106890Simp		panic("no lun info mem");
108667468Snon
1087240172Sjhb	bzero(li, ti->ti_lunsize);
108867468Snon	li->li_lun = lun;
108967468Snon	li->li_ti = ti;
109067468Snon
109179697Snon	li->li_cfgflags = SCSI_LOW_SYNC | SCSI_LOW_LINK | SCSI_LOW_DISC |
109279697Snon			  SCSI_LOW_QTAG;
109379697Snon	li->li_quirks = li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
109479697Snon	li->li_flags_valid = SCSI_LOW_LUN_FLAGS_USER_VALID;
109579697Snon#ifdef	SCSI_LOW_FLAGS_QUIRKS_OK
109679697Snon	li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
109779697Snon#endif	/* SCSI_LOW_FLAGS_QUIRKS_OK */
109879697Snon
109979697Snon	li->li_qtagbits = (u_int) -1;
110079697Snon
110179697Snon	TAILQ_INIT(&li->li_discq);
110267468Snon	LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain);
110367468Snon
110479697Snon	/* host specific structure initialization per lun */
110579697Snon	if (slp->sl_funcs->scsi_low_lun_init != NULL)
110679697Snon		(*slp->sl_funcs->scsi_low_lun_init)
110779697Snon			(slp, ti, li, SCSI_LOW_INFO_ALLOC);
110879697Snon	scsi_low_calcf_lun(li);
110967468Snon	return li;
111067468Snon}
111167468Snon
111267468Snon/**************************************************************
111367468Snon * allocate targ_info
111467468Snon **************************************************************/
111567468Snonstatic struct targ_info *
111679697Snonscsi_low_alloc_ti(slp, targ)
111767468Snon	struct scsi_low_softc *slp;
111879697Snon	int targ;
111967468Snon{
112067468Snon	struct targ_info *ti;
112167468Snon
112271999Sphk	if (TAILQ_FIRST(&slp->sl_titab) == NULL)
112367468Snon		TAILQ_INIT(&slp->sl_titab);
112467468Snon
112579697Snon	ti = SCSI_LOW_MALLOC(slp->sl_targsize);
112667468Snon	if (ti == NULL)
1127240325Sjhb		panic("%s short of memory", device_get_nameunit(slp->sl_dev));
112867468Snon
1129240172Sjhb	bzero(ti, slp->sl_targsize);
113067468Snon	ti->ti_id = targ;
113167468Snon	ti->ti_sc = slp;
113267468Snon
113367468Snon	slp->sl_ti[targ] = ti;
113467468Snon	TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain);
113567468Snon	LIST_INIT(&ti->ti_litab);
113667468Snon
113779697Snon	ti->ti_quirks = ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
113879697Snon	ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
113979697Snon	ti->ti_flags_valid = SCSI_LOW_TARG_FLAGS_USER_VALID;
114079697Snon#ifdef	SCSI_LOW_FLAGS_QUIRKS_OK
114179697Snon	ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
114279697Snon#endif	/* SCSI_LOW_FLAGS_QUIRKS_OK */
114373025Snon
114479697Snon	if (slp->sl_funcs->scsi_low_targ_init != NULL)
114579697Snon	{
114679697Snon		(*slp->sl_funcs->scsi_low_targ_init)
114779697Snon			(slp, ti, SCSI_LOW_INFO_ALLOC);
114879697Snon	}
114979697Snon	scsi_low_calcf_target(ti);
115067468Snon	return ti;
115167468Snon}
115267468Snon
115367468Snonstatic void
115467468Snonscsi_low_free_ti(slp)
115567468Snon	struct scsi_low_softc *slp;
115667468Snon{
115767468Snon	struct targ_info *ti, *tib;
115867468Snon	struct lun_info *li, *nli;
115967468Snon
116071999Sphk	for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib)
116167468Snon	{
116267468Snon		for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli)
116367468Snon		{
116479697Snon			if (slp->sl_funcs->scsi_low_lun_init != NULL)
116579697Snon			{
116679697Snon				(*slp->sl_funcs->scsi_low_lun_init)
116779697Snon					(slp, ti, li, SCSI_LOW_INFO_DEALLOC);
116879697Snon			}
116967468Snon			nli = LIST_NEXT(li, lun_chain);
117079697Snon			SCSI_LOW_FREE(li);
117167468Snon		}
117279697Snon
117379697Snon		if (slp->sl_funcs->scsi_low_targ_init != NULL)
117479697Snon		{
117579697Snon			(*slp->sl_funcs->scsi_low_targ_init)
117679697Snon				(slp, ti, SCSI_LOW_INFO_DEALLOC);
117779697Snon		}
117879697Snon		tib = TAILQ_NEXT(ti, ti_chain);
117979697Snon		SCSI_LOW_FREE(ti);
118067468Snon	}
118167468Snon}
118267468Snon
118367468Snon/**************************************************************
118467468Snon * timeout
118567468Snon **************************************************************/
118667468Snonvoid
118779697Snonscsi_low_bus_idle(slp)
118879697Snon	struct scsi_low_softc *slp;
118979697Snon{
119079697Snon
119179697Snon	slp->sl_retry_sel = 0;
119279697Snon	if (slp->sl_Tnexus == NULL)
119379697Snon		scsi_low_start(slp);
119479697Snon}
119579697Snon
119679697Snonstatic void
119767468Snonscsi_low_timeout(arg)
119867468Snon	void *arg;
119967468Snon{
120067468Snon	struct scsi_low_softc *slp = arg;
120179697Snon
1202274760Sjhb	SCSI_LOW_ASSERT_LOCKED(slp);
120379697Snon	(void) scsi_low_timeout_check(slp);
1204274760Sjhb	callout_schedule(&slp->sl_timeout_timer, hz / SCSI_LOW_TIMEOUT_HZ);
120579697Snon}
120679697Snon
120779697Snonstatic int
120879697Snonscsi_low_timeout_check(slp)
120979697Snon	struct scsi_low_softc *slp;
121079697Snon{
121167468Snon	struct targ_info *ti;
121279697Snon	struct lun_info *li;
121367468Snon	struct slccb *cb = NULL;		/* XXX */
121467468Snon
121579697Snon	/* selection restart */
121679697Snon	if (slp->sl_retry_sel != 0)
121767468Snon	{
121879697Snon		slp->sl_retry_sel = 0;
121979697Snon		if (slp->sl_Tnexus != NULL)
122079697Snon			goto step1;
122167468Snon
122279697Snon		cb = TAILQ_FIRST(&slp->sl_start);
122379697Snon		if (cb == NULL)
122479697Snon			goto step1;
122579697Snon
122679697Snon		if (cb->ccb_selrcnt >= SCSI_LOW_MAX_SELECTION_RETRY)
122767468Snon		{
122879697Snon			cb->ccb_flags |= CCB_NORETRY;
122979697Snon			cb->ccb_error |= SELTIMEOUTIO;
123079697Snon			if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
1231240325Sjhb				panic("%s: ccb not finished",
1232240325Sjhb				    device_get_nameunit(slp->sl_dev));
123367468Snon		}
123479697Snon
123579697Snon		if (slp->sl_Tnexus == NULL)
123679697Snon			scsi_low_start(slp);
123767468Snon	}
123879697Snon
123979697Snon	/* call hardware timeout */
124079697Snonstep1:
124179697Snon	if (slp->sl_funcs->scsi_low_timeout != NULL)
124267468Snon	{
124379697Snon		(*slp->sl_funcs->scsi_low_timeout) (slp);
124479697Snon	}
124579697Snon
124679697Snon	if (slp->sl_timeout_count ++ <
124779697Snon	    SCSI_LOW_TIMEOUT_CHECK_INTERVAL * SCSI_LOW_TIMEOUT_HZ)
124879697Snon		return 0;
124979697Snon
125079697Snon	slp->sl_timeout_count = 0;
125179697Snon	if (slp->sl_nio > 0)
125279697Snon	{
125379697Snon		if ((cb = slp->sl_Qnexus) != NULL)
125467468Snon		{
125567468Snon			cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
125667468Snon			if (cb->ccb_tc < 0)
125767468Snon				goto bus_reset;
125867468Snon		}
125979697Snon		else if (slp->sl_disc == 0)
126067468Snon		{
126179697Snon		        if ((cb = TAILQ_FIRST(&slp->sl_start)) == NULL)
126279697Snon				return 0;
126367468Snon
126479697Snon			cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
126579697Snon			if (cb->ccb_tc < 0)
126679697Snon				goto bus_reset;
126779697Snon		}
126879697Snon		else for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
126979697Snon		          ti = TAILQ_NEXT(ti, ti_chain))
127079697Snon		{
127179697Snon			if (ti->ti_disc == 0)
127279697Snon				continue;
127367468Snon
127479697Snon			for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
127579697Snon			     li = LIST_NEXT(li, lun_chain))
127667468Snon			{
127779697Snon				for (cb = TAILQ_FIRST(&li->li_discq);
127879697Snon				     cb != NULL;
127979697Snon				     cb = TAILQ_NEXT(cb, ccb_chain))
128079697Snon				{
128179697Snon					cb->ccb_tc -=
128279697Snon						SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
128379697Snon					if (cb->ccb_tc < 0)
128479697Snon						goto bus_reset;
128579697Snon				}
128667468Snon			}
128767468Snon		}
128879697Snon
128967468Snon	}
129079697Snon	else if ((slp->sl_flags & HW_POWERCTRL) != 0)
129179697Snon	{
129279697Snon		if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0)
129379697Snon			return 0;
129467468Snon
129579697Snon		if (slp->sl_active != 0)
129679697Snon		{
129779697Snon			slp->sl_powc = SCSI_LOW_POWDOWN_TC;
129879697Snon			slp->sl_active = 0;
129979697Snon			return 0;
130079697Snon		}
130167468Snon
130279697Snon		slp->sl_powc --;
130379697Snon		if (slp->sl_powc < 0)
130479697Snon		{
130579697Snon			slp->sl_powc = SCSI_LOW_POWDOWN_TC;
130679697Snon			slp->sl_flags |= HW_POWDOWN;
130779697Snon			(*slp->sl_funcs->scsi_low_power)
130879697Snon					(slp, SCSI_LOW_POWDOWN);
130979697Snon		}
131079697Snon	}
131179697Snon	return 0;
131267468Snon
131367468Snonbus_reset:
131467468Snon	cb->ccb_error |= TIMEOUTIO;
1315240325Sjhb	device_printf(slp->sl_dev, "slccb (0x%lx) timeout!\n", (u_long) cb);
131667468Snon	scsi_low_info(slp, NULL, "scsi bus hangup. try to recover.");
131767468Snon	scsi_low_init(slp, SCSI_LOW_RESTART_HARD);
131867468Snon	scsi_low_start(slp);
131979697Snon	return ERESTART;
132067468Snon}
132167468Snon
132267468Snon
132379697Snonstatic int
132479697Snonscsi_low_abort_ccb(slp, cb)
132579697Snon	struct scsi_low_softc *slp;
132679697Snon	struct slccb *cb;
132779697Snon{
132879697Snon	struct targ_info *ti;
132979697Snon	struct lun_info *li;
133079697Snon	u_int msg;
133167468Snon
133279697Snon	if (cb == NULL)
133379697Snon		return EINVAL;
133479697Snon	if ((cb->ccb_omsgoutflag &
133579697Snon	     (SCSI_LOW_MSG_ABORT | SCSI_LOW_MSG_ABORT_QTAG)) != 0)
133679697Snon		return EBUSY;
133767468Snon
133879697Snon	ti = cb->ti;
133979697Snon	li = cb->li;
134079697Snon	if (cb->ccb_tag == SCSI_LOW_UNKTAG)
134179697Snon		msg = SCSI_LOW_MSG_ABORT;
134279697Snon	else
134379697Snon		msg = SCSI_LOW_MSG_ABORT_QTAG;
134467468Snon
134579697Snon	cb->ccb_error |= ABORTIO;
134679697Snon	cb->ccb_flags |= CCB_NORETRY;
134779697Snon	scsi_low_ccb_message_assert(cb, msg);
134867468Snon
134979697Snon	if (cb == slp->sl_Qnexus)
135079697Snon	{
135179697Snon		scsi_low_assert_msg(slp, ti, msg, 1);
135279697Snon	}
135379697Snon	else if ((cb->ccb_flags & CCB_DISCQ) != 0)
135479697Snon	{
135579697Snon		if (scsi_low_revoke_ccb(slp, cb, 0) == NULL)
1356240325Sjhb			panic("%s: revoked ccb done",
1357240325Sjhb			    device_get_nameunit(slp->sl_dev));
135867468Snon
135979697Snon		cb->ccb_flags |= CCB_STARTQ;
136079697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
136167468Snon
136279697Snon		if (slp->sl_Tnexus == NULL)
136379697Snon			scsi_low_start(slp);
136479697Snon	}
136579697Snon	else
136679697Snon	{
136779697Snon		if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
1368240325Sjhb			panic("%s: revoked ccb retried",
1369240325Sjhb			    device_get_nameunit(slp->sl_dev));
137079697Snon	}
137179697Snon	return 0;
137267468Snon}
137367468Snon
137479697Snon/**************************************************************
137579697Snon * Generic SCSI INTERFACE
137679697Snon **************************************************************/
137767468Snonint
137879697Snonscsi_low_attach(slp, openings, ntargs, nluns, targsize, lunsize)
137967468Snon	struct scsi_low_softc *slp;
138079697Snon	int openings, ntargs, nluns, targsize, lunsize;
138167468Snon{
138267468Snon	struct targ_info *ti;
138367468Snon	struct lun_info *li;
1384274760Sjhb	int i, nccb, rv;
138567468Snon
138667468Snon	if (ntargs > SCSI_LOW_NTARGETS)
138767468Snon	{
138867468Snon		printf("scsi_low: %d targets are too large\n", ntargs);
138967468Snon		printf("change kernel options SCSI_LOW_NTARGETS");
139079697Snon		return EINVAL;
139167468Snon	}
139267468Snon
139379697Snon	if (openings <= 0)
139479697Snon		slp->sl_openings = (SCSI_LOW_NCCB / ntargs);
139579697Snon	else
139679697Snon		slp->sl_openings = openings;
139779697Snon	slp->sl_ntargs = ntargs;
139879697Snon	slp->sl_nluns = nluns;
139979697Snon	slp->sl_max_retry = SCSI_LOW_MAX_RETRY;
140067468Snon
140179697Snon	if (lunsize < sizeof(struct lun_info))
140279697Snon		lunsize = sizeof(struct lun_info);
140379697Snon
140479697Snon	if (targsize < sizeof(struct targ_info))
140579697Snon		targsize = sizeof(struct targ_info);
140679697Snon
140779697Snon	slp->sl_targsize = targsize;
140867468Snon	for (i = 0; i < ntargs; i ++)
140967468Snon	{
141079697Snon		ti = scsi_low_alloc_ti(slp, i);
141179697Snon		ti->ti_lunsize = lunsize;
141267468Snon		li = scsi_low_alloc_li(ti, 0, 1);
141367468Snon	}
141467468Snon
141567468Snon	/* initialize queue */
141679697Snon	nccb = openings * ntargs;
141767468Snon	if (nccb >= SCSI_LOW_NCCB || nccb <= 0)
141867468Snon		nccb = SCSI_LOW_NCCB;
141967468Snon	scsi_low_init_ccbque(nccb);
142067468Snon	TAILQ_INIT(&slp->sl_start);
142167468Snon
142279697Snon	/* call os depend attach */
1423274760Sjhb	rv = scsi_low_attach_cam(slp);
142479697Snon	if (rv != 0)
142579697Snon	{
1426240325Sjhb		device_printf(slp->sl_dev,
1427240325Sjhb		    "scsi_low_attach: osdep attach failed\n");
1428274760Sjhb		return (rv);
142979697Snon	}
143067468Snon
143179697Snon	/* check hardware */
1432240172Sjhb	DELAY(1000);	/* wait for 1ms */
1433274760Sjhb	SCSI_LOW_LOCK(slp);
143479697Snon	if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0)
143579697Snon	{
1436240325Sjhb		device_printf(slp->sl_dev,
1437240325Sjhb		    "scsi_low_attach: initialization failed\n");
1438274760Sjhb		SCSI_LOW_UNLOCK(slp);
143979697Snon		return EINVAL;
144079697Snon	}
144167468Snon
144267468Snon	/* start watch dog */
144379697Snon	slp->sl_timeout_count = 0;
1444274760Sjhb	callout_reset(&slp->sl_timeout_timer, hz / SCSI_LOW_TIMEOUT_HZ,
1445274760Sjhb	    scsi_low_timeout, slp);
1446274760Sjhb	mtx_lock(&sl_tab_lock);
144779697Snon	LIST_INSERT_HEAD(&sl_tab, slp, sl_chain);
1448274760Sjhb	mtx_unlock(&sl_tab_lock);
144967468Snon
145079697Snon	/* fake call */
145179697Snon	scsi_low_abort_ccb(slp, scsi_low_find_ccb(slp, 0, 0, NULL));
145267468Snon
145379697Snon#ifdef	SCSI_LOW_START_UP_CHECK
145479697Snon	/* probing devices */
145579697Snon	scsi_low_start_up(slp);
145679697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
1457274760Sjhb	SCSI_LOW_UNLOCK(slp);
145867468Snon
145979697Snon	return 0;
146067468Snon}
146167468Snon
146267468Snonint
1463274760Sjhbscsi_low_detach(slp)
146467468Snon	struct scsi_low_softc *slp;
146567468Snon{
1466274760Sjhb	int rv;
146767468Snon
1468274760Sjhb	SCSI_LOW_LOCK(slp);
146979697Snon	if (scsi_low_is_busy(slp) != 0)
147079697Snon	{
1471274760Sjhb		SCSI_LOW_UNLOCK(slp);
147267468Snon		return EBUSY;
147379697Snon	}
147467468Snon
147579697Snon	scsi_low_deactivate(slp);
147667468Snon
1477274760Sjhb	rv = scsi_low_detach_cam(slp);
147879697Snon	if (rv != 0)
147979697Snon	{
1480274760Sjhb		SCSI_LOW_UNLOCK(slp);
148179697Snon		return EBUSY;
148279697Snon	}
148367468Snon
148467468Snon	scsi_low_free_ti(slp);
1485274760Sjhb	SCSI_LOW_UNLOCK(slp);
1486274760Sjhb	callout_drain(&slp->sl_timeout_timer);
1487274760Sjhb	callout_drain(&slp->sl_engage_timer);
1488274760Sjhb	mtx_lock(&sl_tab_lock);
148979697Snon	LIST_REMOVE(slp, sl_chain);
1490274760Sjhb	mtx_unlock(&sl_tab_lock);
149167468Snon	return 0;
149267468Snon}
149367468Snon
149479697Snon/**************************************************************
149579697Snon * Generic enqueue
149679697Snon **************************************************************/
149779697Snonstatic int
149879697Snonscsi_low_enqueue(slp, ti, li, cb, flags, msg)
149979697Snon	struct scsi_low_softc *slp;
150067468Snon	struct targ_info *ti;
150167468Snon	struct lun_info *li;
150267468Snon	struct slccb *cb;
150379697Snon	u_int flags, msg;
150479697Snon{
150567468Snon
150679697Snon	cb->ti = ti;
150779697Snon	cb->li = li;
150867468Snon
150979697Snon	scsi_low_ccb_message_assert(cb, msg);
151067468Snon
151179697Snon	cb->ccb_otag = cb->ccb_tag = SCSI_LOW_UNKTAG;
151279697Snon	scsi_low_alloc_qtag(cb);
151367468Snon
151479697Snon	cb->ccb_flags = flags | CCB_STARTQ;
151579697Snon	cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
151679697Snon	cb->ccb_error |= PENDINGIO;
151779697Snon
151879697Snon	if ((flags & CCB_URGENT) != 0)
151979697Snon	{
152079697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
152179697Snon	}
152279697Snon	else
152379697Snon	{
152467468Snon		TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain);
152579697Snon	}
152667468Snon
152779697Snon	slp->sl_nio ++;
152867468Snon
152979697Snon	if (slp->sl_Tnexus == NULL)
153079697Snon		scsi_low_start(slp);
153179697Snon	return 0;
153279697Snon}
153367468Snon
153479697Snonstatic int
153579697Snonscsi_low_message_enqueue(slp, ti, li, flags)
153679697Snon	struct scsi_low_softc *slp;
153779697Snon	struct targ_info *ti;
153879697Snon	struct lun_info *li;
153979697Snon	u_int flags;
154079697Snon{
154179697Snon	struct slccb *cb;
154279697Snon	u_int tmsgflags;
154367468Snon
154479697Snon	tmsgflags = ti->ti_setup_msg;
154579697Snon	ti->ti_setup_msg = 0;
154667468Snon
154779697Snon	flags |= CCB_NORETRY;
154879697Snon	if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
154979697Snon		return ENOMEM;
155067468Snon
155179697Snon	cb->osdep = NULL;
155279697Snon	cb->bp = NULL;
155379697Snon	scsi_low_enqueue(slp, ti, li, cb, flags, tmsgflags);
155479697Snon	return 0;
155579697Snon}
155667468Snon
155779697Snon/**************************************************************
155879697Snon * Generic Start & Done
155979697Snon **************************************************************/
156079697Snon#define	SLSC_MODE_SENSE_SHORT   0x1a
156179697Snonstatic u_int8_t ss_cmd[6] = {START_STOP, 0, 0, 0, SSS_START, 0};
156279697Snonstatic u_int8_t sms_cmd[6] = {SLSC_MODE_SENSE_SHORT, 0x08, 0x0a, 0,
156379697Snon			      sizeof(struct scsi_low_mode_sense_data), 0};
156479697Snonstatic u_int8_t inq_cmd[6] = {INQUIRY, 0, 0, 0,
156579697Snon			      sizeof(struct scsi_low_inq_data), 0};
156679697Snonstatic u_int8_t unit_ready_cmd[6];
156792770Salfredstatic int scsi_low_setup_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *);
156892770Salfredstatic int scsi_low_sense_abort_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *);
156992770Salfredstatic int scsi_low_resume(struct scsi_low_softc *);
157079697Snon
157179697Snonstatic void
157279697Snonscsi_low_unit_ready_cmd(cb)
157379697Snon	struct slccb *cb;
157479697Snon{
157579697Snon
157679697Snon	cb->ccb_scp.scp_cmd = unit_ready_cmd;
157779697Snon	cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd);
157879697Snon	cb->ccb_scp.scp_datalen = 0;
157979697Snon	cb->ccb_scp.scp_direction = SCSI_LOW_READ;
158079697Snon	cb->ccb_tcmax = 15;
158167468Snon}
158279697Snon
158367468Snonstatic int
158479697Snonscsi_low_sense_abort_start(slp, ti, li, cb)
158579697Snon	struct scsi_low_softc *slp;
158667468Snon	struct targ_info *ti;
158779697Snon	struct lun_info *li;
158867468Snon	struct slccb *cb;
158979697Snon{
159067468Snon
159179697Snon	cb->ccb_scp.scp_cmdlen = 6;
1592240172Sjhb	bzero(cb->ccb_scsi_cmd, cb->ccb_scp.scp_cmdlen);
159379697Snon	cb->ccb_scsi_cmd[0] = REQUEST_SENSE;
159479697Snon	cb->ccb_scsi_cmd[4] = sizeof(cb->ccb_sense);
159579697Snon	cb->ccb_scp.scp_cmd = cb->ccb_scsi_cmd;
159679697Snon	cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense;
159779697Snon	cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense);
159879697Snon	cb->ccb_scp.scp_direction = SCSI_LOW_READ;
159979697Snon	cb->ccb_tcmax = 15;
160079697Snon	scsi_low_ccb_message_clear(cb);
160179697Snon	if ((cb->ccb_flags & CCB_CLEARQ) != 0)
160267468Snon	{
160379697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
160467468Snon	}
160579697Snon	else
160679697Snon	{
1607240172Sjhb		bzero(&cb->ccb_sense, sizeof(cb->ccb_sense));
160879697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
160979697Snon		scsi_low_assert_msg(slp, ti, ti->ti_setup_msg_done, 0);
161079697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
161179697Snon	}
161267468Snon
161379697Snon	return SCSI_LOW_START_NO_QTAG;
161479697Snon}
161567468Snon
161679697Snonstatic int
161779697Snonscsi_low_setup_start(slp, ti, li, cb)
161879697Snon	struct scsi_low_softc *slp;
161979697Snon	struct targ_info *ti;
162079697Snon	struct lun_info *li;
162179697Snon	struct slccb *cb;
162279697Snon{
162367468Snon
162479697Snon	switch(li->li_state)
162579697Snon	{
162679697Snon	case SCSI_LOW_LUN_SLEEP:
162779697Snon		scsi_low_unit_ready_cmd(cb);
162879697Snon		break;
162967468Snon
163079697Snon	case SCSI_LOW_LUN_START:
163179697Snon		cb->ccb_scp.scp_cmd = ss_cmd;
163279697Snon		cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd);
163379697Snon		cb->ccb_scp.scp_datalen = 0;
163479697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
163579697Snon		cb->ccb_tcmax = 30;
163679697Snon		break;
163767468Snon
163879697Snon	case SCSI_LOW_LUN_INQ:
163979697Snon		cb->ccb_scp.scp_cmd = inq_cmd;
164079697Snon		cb->ccb_scp.scp_cmdlen = sizeof(inq_cmd);
164179697Snon		cb->ccb_scp.scp_data = (u_int8_t *)&li->li_inq;
164279697Snon		cb->ccb_scp.scp_datalen = sizeof(li->li_inq);
164379697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
164479697Snon		cb->ccb_tcmax = 15;
164579697Snon		break;
164667468Snon
164779697Snon	case SCSI_LOW_LUN_MODEQ:
164879697Snon		cb->ccb_scp.scp_cmd = sms_cmd;
164979697Snon		cb->ccb_scp.scp_cmdlen = sizeof(sms_cmd);
165079697Snon		cb->ccb_scp.scp_data = (u_int8_t *)&li->li_sms;
165179697Snon		cb->ccb_scp.scp_datalen = sizeof(li->li_sms);
165279697Snon		cb->ccb_scp.scp_direction = SCSI_LOW_READ;
165379697Snon		cb->ccb_tcmax = 15;
165479697Snon		return SCSI_LOW_START_QTAG;
165567468Snon
165679697Snon	default:
1657240325Sjhb		panic("%s: no setup phase", device_get_nameunit(slp->sl_dev));
165867468Snon	}
165967468Snon
166079697Snon	return SCSI_LOW_START_NO_QTAG;
166167468Snon}
166267468Snon
166379697Snonstatic int
166479697Snonscsi_low_resume(slp)
166579697Snon	struct scsi_low_softc *slp;
166667468Snon{
166767468Snon
166879697Snon	if (slp->sl_flags & HW_RESUME)
166979697Snon		return EJUSTRETURN;
167079697Snon	slp->sl_flags &= ~HW_POWDOWN;
167179697Snon	if (slp->sl_funcs->scsi_low_power != NULL)
167279697Snon	{
167379697Snon		slp->sl_flags |= HW_RESUME;
167479697Snon		slp->sl_rstep = 0;
167579697Snon		(*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
1676274760Sjhb		callout_reset(&slp->sl_engage_timer, hz / 1000,
1677274760Sjhb		    scsi_low_engage, slp);
167879697Snon		return EJUSTRETURN;
167979697Snon	}
168079697Snon	return 0;
168167468Snon}
168267468Snon
168367468Snonstatic void
168467468Snonscsi_low_start(slp)
168567468Snon	struct scsi_low_softc *slp;
168667468Snon{
168767468Snon	struct targ_info *ti;
168867468Snon	struct lun_info *li;
168967468Snon	struct slccb *cb;
169067468Snon	int rv;
169167468Snon
169279697Snon	/* check hardware exists or under initializations ? */
169379697Snon	if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0)
169467468Snon		return;
169567468Snon
169667468Snon	/* check hardware power up ? */
169767468Snon	if ((slp->sl_flags & HW_POWERCTRL) != 0)
169867468Snon	{
169967468Snon		slp->sl_active ++;
170067468Snon		if (slp->sl_flags & (HW_POWDOWN | HW_RESUME))
170167468Snon		{
170279697Snon			if (scsi_low_resume(slp) == EJUSTRETURN)
170367468Snon				return;
170467468Snon		}
170567468Snon	}
170667468Snon
170767468Snon	/* setup nexus */
170867468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
170979697Snon	if (slp->sl_Tnexus || slp->sl_Lnexus || slp->sl_Qnexus)
171067468Snon	{
171167468Snon		scsi_low_info(slp, NULL, "NEXUS INCOSISTENT");
1712240325Sjhb		panic("%s: inconsistent", device_get_nameunit(slp->sl_dev));
171367468Snon	}
171467468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
171567468Snon
171679697Snon	for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL;
171779697Snon	     cb = TAILQ_NEXT(cb, ccb_chain))
171867468Snon	{
171967468Snon		li = cb->li;
172079697Snon
172179697Snon		if (li->li_disc == 0)
172279697Snon		{
172367468Snon			goto scsi_low_cmd_start;
172479697Snon		}
172579697Snon		else if (li->li_nqio > 0)
172679697Snon		{
172779697Snon			if (li->li_nqio < li->li_maxnqio ||
172879697Snon		            (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
172979697Snon				goto scsi_low_cmd_start;
173079697Snon		}
173167468Snon	}
173267468Snon	return;
173367468Snon
173467468Snonscsi_low_cmd_start:
173579697Snon	cb->ccb_flags &= ~CCB_STARTQ;
173679697Snon	TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
173779697Snon	ti = cb->ti;
173867468Snon
173967468Snon	/* clear all error flag bits (for restart) */
174067468Snon	cb->ccb_error = 0;
174179697Snon	cb->ccb_datalen = -1;
174279697Snon	cb->ccb_scp.scp_status = ST_UNKNOWN;
174367468Snon
174467468Snon	/* setup nexus pointer */
174579697Snon	slp->sl_Qnexus = cb;
174679697Snon	slp->sl_Lnexus = li;
174779697Snon	slp->sl_Tnexus = ti;
174867468Snon
174967468Snon	/* initialize msgsys */
175067468Snon	scsi_low_init_msgsys(slp, ti);
175167468Snon
175279697Snon	/* exec cmd */
175379697Snon	if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
175467468Snon	{
175579697Snon		/* CA state or forced abort */
175679697Snon		rv = scsi_low_sense_abort_start(slp, ti, li, cb);
175767468Snon	}
175879697Snon	else if (li->li_state >= SCSI_LOW_LUN_OK)
175967468Snon	{
176079697Snon		cb->ccb_flags &= ~CCB_INTERNAL;
1761274760Sjhb		rv = scsi_low_ccb_setup_cam(slp, cb);
176279697Snon		if (cb->ccb_msgoutflag != 0)
176379697Snon		{
176479697Snon			scsi_low_ccb_message_exec(slp, cb);
176579697Snon		}
176667468Snon	}
176779697Snon	else
176867468Snon	{
176979697Snon		cb->ccb_flags |= CCB_INTERNAL;
177079697Snon		rv = scsi_low_setup_start(slp, ti, li, cb);
177179697Snon	}
177267468Snon
177379697Snon	/* allocate qtag */
177479697Snon#define	SCSI_LOW_QTAG_OK (SCSI_LOW_QTAG | SCSI_LOW_DISC)
177567468Snon
177679697Snon	if (rv == SCSI_LOW_START_QTAG &&
177779697Snon	    (li->li_flags & SCSI_LOW_QTAG_OK) == SCSI_LOW_QTAG_OK &&
177879697Snon	    li->li_maxnqio > 0)
177979697Snon	{
178079697Snon		u_int qmsg;
178167468Snon
178279697Snon		scsi_low_activate_qtag(cb);
178379697Snon		if ((scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
178479697Snon		     SCSI_LOW_CMD_ORDERED_QTAG) != 0)
178579697Snon			qmsg = SCSI_LOW_MSG_ORDERED_QTAG;
178679697Snon		else if ((cb->ccb_flags & CCB_URGENT) != 0)
178779697Snon			qmsg = SCSI_LOW_MSG_HEAD_QTAG;
178879697Snon		else
178979697Snon			qmsg = SCSI_LOW_MSG_SIMPLE_QTAG;
179079697Snon		scsi_low_assert_msg(slp, ti, qmsg, 0);
179167468Snon	}
179267468Snon
179367468Snon	/* timeout */
179467468Snon	if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT)
179567468Snon		cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
179667468Snon	cb->ccb_tc = cb->ccb_tcmax;
179767468Snon
179867468Snon	/* setup saved scsi data pointer */
179967468Snon	cb->ccb_sscp = cb->ccb_scp;
180067468Snon
180167468Snon	/* setup current scsi pointer */
180267468Snon	slp->sl_scp = cb->ccb_sscp;
180367468Snon	slp->sl_error = cb->ccb_error;
180467468Snon
180579697Snon	/* assert always an identify msg */
180679697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
180779697Snon
180879697Snon	/* debug section */
180979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
181079697Snon	scsi_low_msg_log_init(&ti->ti_log_msgin);
181179697Snon	scsi_low_msg_log_init(&ti->ti_log_msgout);
181279697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
181379697Snon
181467468Snon	/* selection start */
181579697Snon	slp->sl_selid = cb;
181667468Snon	rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb));
181767468Snon	if (rv == SCSI_LOW_START_OK)
181867468Snon	{
181967468Snon#ifdef	SCSI_LOW_STATICS
182067468Snon		scsi_low_statics.nexus_win ++;
182167468Snon#endif	/* SCSI_LOW_STATICS */
182267468Snon		return;
182367468Snon	}
182467468Snon
182579697Snon	scsi_low_arbit_fail(slp, cb);
182667468Snon#ifdef	SCSI_LOW_STATICS
182767468Snon	scsi_low_statics.nexus_fail ++;
182867468Snon#endif	/* SCSI_LOW_STATICS */
182967468Snon}
183067468Snon
183167468Snonvoid
183279697Snonscsi_low_arbit_fail(slp, cb)
183367468Snon	struct scsi_low_softc *slp;
183479697Snon	struct slccb *cb;
183579697Snon{
183679697Snon	struct targ_info *ti = cb->ti;
183779697Snon
183879697Snon	scsi_low_deactivate_qtag(cb);
183979697Snon	scsi_low_ccb_message_retry(cb);
184079697Snon	cb->ccb_flags |= CCB_STARTQ;
184179697Snon	TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
184279697Snon
184379697Snon	scsi_low_bus_release(slp, ti);
184479697Snon
184579697Snon	cb->ccb_selrcnt ++;
184679697Snon	if (slp->sl_disc == 0)
184779697Snon	{
184879697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
1849240325Sjhb		device_printf(slp->sl_dev, "try selection again\n");
185079697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
185179697Snon		slp->sl_retry_sel = 1;
185279697Snon	}
185379697Snon}
185479697Snon
185579697Snonstatic void
185679697Snonscsi_low_bus_release(slp, ti)
185779697Snon	struct scsi_low_softc *slp;
185867468Snon	struct targ_info *ti;
185967468Snon{
186067468Snon
186179697Snon	if (ti->ti_disc > 0)
186279697Snon	{
186379697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DISC);
186479697Snon	}
186579697Snon	else
186679697Snon	{
186779697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
186879697Snon	}
186979697Snon
187067468Snon	/* clear all nexus pointer */
187179697Snon	slp->sl_Qnexus = NULL;
187279697Snon	slp->sl_Lnexus = NULL;
187379697Snon	slp->sl_Tnexus = NULL;
187467468Snon
187567468Snon	/* clear selection assert */
187667468Snon	slp->sl_selid = NULL;
187767468Snon
187867468Snon	/* clear nexus data */
187967468Snon	slp->sl_scp.scp_direction = SCSI_LOW_RWUNK;
188079697Snon
188179697Snon	/* clear phase change counter */
188279697Snon	slp->sl_ph_count = 0;
188367468Snon}
188467468Snon
188567468Snonstatic int
188679697Snonscsi_low_setup_done(slp, cb)
188767468Snon	struct scsi_low_softc *slp;
188867468Snon	struct slccb *cb;
188967468Snon{
189067468Snon	struct targ_info *ti;
189167468Snon	struct lun_info *li;
189267468Snon
189367468Snon	ti = cb->ti;
189467468Snon	li = cb->li;
189579697Snon
189679697Snon	if (cb->ccb_rcnt >= slp->sl_max_retry)
189767468Snon	{
189879697Snon		cb->ccb_error |= ABORTIO;
189979697Snon		return SCSI_LOW_DONE_COMPLETE;
190079697Snon	}
190179697Snon
190279697Snon	/* XXX: special huck for selection timeout */
190379697Snon	if (li->li_state == SCSI_LOW_LUN_SLEEP &&
190479697Snon	    (cb->ccb_error & SELTIMEOUTIO) != 0)
190579697Snon	{
190679697Snon		cb->ccb_error |= ABORTIO;
190779697Snon		return SCSI_LOW_DONE_COMPLETE;
190879697Snon	}
190979697Snon
191079697Snon	switch(li->li_state)
191179697Snon	{
191279697Snon	case SCSI_LOW_LUN_INQ:
191379697Snon		if (cb->ccb_error != 0)
191467468Snon		{
191579697Snon			li->li_diskflags &=
191679697Snon				~(SCSI_LOW_DISK_LINK | SCSI_LOW_DISK_QTAG);
191779697Snon			if (li->li_lun > 0)
191879697Snon				goto resume;
191979697Snon			ti->ti_diskflags &=
192079697Snon				~(SCSI_LOW_DISK_SYNC | SCSI_LOW_DISK_WIDE);
192167468Snon		}
192279697Snon		else if ((li->li_inq.sd_version & 7) >= 2 ||
192379697Snon		         (li->li_inq.sd_len >= 4))
192467468Snon		{
192579697Snon			if ((li->li_inq.sd_support & 0x2) == 0)
192679697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
192779697Snon			if ((li->li_inq.sd_support & 0x8) == 0)
192879697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_LINK;
192979697Snon			if (li->li_lun > 0)
193079697Snon				goto resume;
193179697Snon			if ((li->li_inq.sd_support & 0x10) == 0)
193279697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_SYNC;
193379697Snon			if ((li->li_inq.sd_support & 0x20) == 0)
193479697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_16;
193579697Snon			if ((li->li_inq.sd_support & 0x40) == 0)
193679697Snon				ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_32;
193779697Snon		}
193879697Snon		else
193979697Snon		{
194079697Snon			li->li_diskflags &=
194179697Snon				~(SCSI_LOW_DISK_QTAG | SCSI_LOW_DISK_LINK);
194279697Snon			if (li->li_lun > 0)
194379697Snon				goto resume;
194479697Snon			ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE;
194579697Snon		}
194679697Snon		ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_DISK_VALID;
194779697Snonresume:
194879697Snon		scsi_low_calcf_target(ti);
194979697Snon		scsi_low_calcf_lun(li);
195079697Snon		break;
195179697Snon
195279697Snon	case SCSI_LOW_LUN_MODEQ:
195379697Snon		if (cb->ccb_error != 0)
195479697Snon		{
195579697Snon			if (cb->ccb_error & SENSEIO)
195667468Snon			{
195779697Snon#ifdef	SCSI_LOW_DEBUG
195879697Snon				if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE)
195979697Snon				{
1960225950Sken					int error_code, sense_key, asc, ascq;
1961225950Sken
1962225950Sken					scsi_extract_sense(&cb->ccb_sense,
1963225950Sken							   &error_code,
1964225950Sken							   &sense_key,
1965225950Sken							   &asc,
1966225950Sken							   &ascq);
1967225950Sken					printf("SENSE: [%x][%x][%x][%x]\n",
1968225950Sken					       error_code, sense_key, asc,
1969225950Sken					       ascq);
197079697Snon				}
197179697Snon#endif	/* SCSI_LOW_DEBUG */
197267468Snon			}
197379697Snon			else
197479697Snon			{
197579697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
197679697Snon			}
197779697Snon		}
197879697Snon		else if ((li->li_sms.sms_cmp.cmp_page & 0x3f) == 0x0a)
197979697Snon		{
198079697Snon			if (li->li_sms.sms_cmp.cmp_qc & 0x02)
198179697Snon				li->li_qflags |= SCSI_LOW_QFLAG_CA_QCLEAR;
198279697Snon			else
198379697Snon				li->li_qflags &= ~SCSI_LOW_QFLAG_CA_QCLEAR;
198479697Snon			if ((li->li_sms.sms_cmp.cmp_qc & 0x01) != 0)
198579697Snon				li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
198679697Snon		}
198779697Snon		li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_DISK_VALID;
198879697Snon		scsi_low_calcf_lun(li);
198979697Snon		break;
199067468Snon
199179697Snon	default:
199279697Snon		break;
199379697Snon	}
199479697Snon
199579697Snon	li->li_state ++;
199679697Snon	if (li->li_state == SCSI_LOW_LUN_OK)
199779697Snon	{
199879697Snon		scsi_low_calcf_target(ti);
199979697Snon		scsi_low_calcf_lun(li);
200079697Snon		if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID &&
200179697Snon	            (slp->sl_show_result & SHOW_CALCF_RES) != 0)
200279697Snon		{
200379697Snon			scsi_low_calcf_show(li);
200479697Snon		}
200579697Snon	}
200679697Snon
200779697Snon	cb->ccb_rcnt --;
200879697Snon	return SCSI_LOW_DONE_RETRY;
200979697Snon}
201079697Snon
201179697Snonstatic int
201279697Snonscsi_low_done(slp, cb)
201379697Snon	struct scsi_low_softc *slp;
201479697Snon	struct slccb *cb;
201579697Snon{
201679697Snon	int rv;
201779697Snon
201879697Snon	if (cb->ccb_error == 0)
201979697Snon	{
202079697Snon		if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
202179697Snon		{
202279697Snon#ifdef	SCSI_LOW_QCLEAR_AFTER_CA
202379697Snon			/* XXX:
202479697Snon			 * SCSI-2 draft suggests
202579697Snon			 * page 0x0a QErr bit determins if
202679697Snon			 * the target aborts or continues
202779697Snon			 * the queueing io's after CA state resolved.
202879697Snon			 * However many targets seem not to support
202979697Snon			 * the page 0x0a. Thus we should manually clear the
203079697Snon			 * queuing io's after CA state.
203179697Snon			 */
203279697Snon			if ((cb->ccb_flags & CCB_CLEARQ) == 0)
203367468Snon			{
203479697Snon				cb->ccb_rcnt --;
203579697Snon				cb->ccb_flags |= CCB_CLEARQ;
203679697Snon				goto retry;
203779697Snon			}
203879697Snon#endif	/* SCSI_LOW_QCLEAR_AFTER_CA */
203979697Snon
204079697Snon			if ((cb->ccb_flags & CCB_SENSE) != 0)
204179697Snon				cb->ccb_error |= (SENSEIO | ABORTIO);
204279697Snon			cb->ccb_flags &= ~(CCB_SENSE | CCB_CLEARQ);
204379697Snon		}
204479697Snon		else switch (cb->ccb_sscp.scp_status)
204579697Snon		{
204679697Snon		case ST_GOOD:
204779697Snon		case ST_MET:
204879697Snon		case ST_INTERGOOD:
204979697Snon		case ST_INTERMET:
205079697Snon			if (cb->ccb_datalen == 0 ||
205179697Snon			    cb->ccb_scp.scp_datalen == 0)
205267468Snon				break;
205367468Snon
205479697Snon			if (cb->ccb_scp.scp_cmdlen > 0 &&
205579697Snon			    (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
205679697Snon			     SCSI_LOW_CMD_RESIDUAL_CHK) == 0)
205779697Snon				break;
205879697Snon
205967468Snon			cb->ccb_error |= PDMAERR;
206067468Snon			break;
206167468Snon
206279697Snon		case ST_BUSY:
206379697Snon		case ST_QUEFULL:
206479697Snon			cb->ccb_error |= (BUSYERR | STATERR);
206579697Snon			break;
206679697Snon
206779697Snon		case ST_CONFLICT:
206879697Snon			cb->ccb_error |= (STATERR | ABORTIO);
206979697Snon			break;
207079697Snon
207167468Snon		case ST_CHKCOND:
207279697Snon		case ST_CMDTERM:
207379697Snon			if (cb->ccb_flags & (CCB_AUTOSENSE | CCB_INTERNAL))
207479697Snon			{
207579697Snon				cb->ccb_rcnt --;
207673025Snon				cb->ccb_flags |= CCB_SENSE;
207773025Snon				goto retry;
207873025Snon			}
207979697Snon			cb->ccb_error |= (UACAERR | STATERR | ABORTIO);
208073025Snon			break;
208167468Snon
208279697Snon		case ST_UNKNOWN:
208367468Snon		default:
208467468Snon			cb->ccb_error |= FATALIO;
208567468Snon			break;
208667468Snon		}
208767468Snon	}
208867468Snon	else
208967468Snon	{
209079697Snon		if (cb->ccb_flags & CCB_SENSE)
209167468Snon		{
209279697Snon			cb->ccb_error |= (SENSEERR | ABORTIO);
209367468Snon		}
209479697Snon		cb->ccb_flags &= ~(CCB_CLEARQ | CCB_SENSE);
209579697Snon	}
209667468Snon
209779697Snon	/* internal ccb */
209879697Snon	if ((cb->ccb_flags & CCB_INTERNAL) != 0)
209979697Snon	{
210079697Snon		if (scsi_low_setup_done(slp, cb) == SCSI_LOW_DONE_RETRY)
210179697Snon			goto retry;
210267468Snon	}
210367468Snon
210479697Snon	/* check a ccb msgout flag */
210579697Snon	if (cb->ccb_omsgoutflag != 0)
210667468Snon	{
210779697Snon#define	SCSI_LOW_MSG_ABORT_OK	(SCSI_LOW_MSG_ABORT | \
210879697Snon				 SCSI_LOW_MSG_ABORT_QTAG | \
210979697Snon				 SCSI_LOW_MSG_CLEAR_QTAG | \
211079697Snon				 SCSI_LOW_MSG_TERMIO)
211179697Snon
211279697Snon		if ((cb->ccb_omsgoutflag & SCSI_LOW_MSG_ABORT_OK) != 0)
211367468Snon		{
211479697Snon			cb->ccb_error |= ABORTIO;
211567468Snon		}
211667468Snon	}
211767468Snon
211879697Snon	/* call OS depend done */
211979697Snon	if (cb->osdep != NULL)
212067468Snon	{
2121274760Sjhb		rv = scsi_low_done_cam(slp, cb);
212279697Snon		if (rv == EJUSTRETURN)
212379697Snon			goto retry;
212467468Snon	}
212579697Snon	else if (cb->ccb_error != 0)
212667468Snon	{
212779697Snon	        if (cb->ccb_rcnt >= slp->sl_max_retry)
212879697Snon			cb->ccb_error |= ABORTIO;
212979697Snon
213079697Snon		if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
213179697Snon		    (cb->ccb_error & ABORTIO) == 0)
213267468Snon			goto retry;
213367468Snon	}
213479697Snon
213579697Snon	/* free our target */
213679697Snon#ifdef	SCSI_LOW_DEBUG
213779697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
213867468Snon	{
213979697Snon		printf(">> SCSI_LOW_DONE_COMPLETE ===============\n");
214079697Snon		scsi_low_print(slp, NULL);
214167468Snon	}
214279697Snon#endif	/* SCSI_LOW_DEBUG */
214367468Snon
214479697Snon	scsi_low_deactivate_qtag(cb);
214579697Snon	scsi_low_dealloc_qtag(cb);
214667468Snon	scsi_low_free_ccb(cb);
214779697Snon	slp->sl_nio --;
214867468Snon	return SCSI_LOW_DONE_COMPLETE;
214967468Snon
215067468Snonretry:
215179697Snon#ifdef	SCSI_LOW_DEBUG
215279697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
215367468Snon	{
215479697Snon		printf("** SCSI_LOW_DONE_RETRY ===============\n");
215579697Snon		scsi_low_print(slp, NULL);
215667468Snon	}
215779697Snon#endif	/* SCSI_LOW_DEBUG */
215879697Snon
215979697Snon	cb->ccb_rcnt ++;
216079697Snon	scsi_low_deactivate_qtag(cb);
216179697Snon	scsi_low_ccb_message_retry(cb);
216267468Snon	return SCSI_LOW_DONE_RETRY;
216367468Snon}
216467468Snon
216567468Snon/**************************************************************
216667468Snon * Reset
216767468Snon **************************************************************/
216867468Snonstatic void
216979697Snonscsi_low_reset_nexus_target(slp, ti, fdone)
217079697Snon	struct scsi_low_softc *slp;
217179697Snon	struct targ_info *ti;
217279697Snon	int fdone;
217367468Snon{
217479697Snon	struct lun_info *li;
217567468Snon
217679697Snon	for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
217779697Snon	     li = LIST_NEXT(li, lun_chain))
217879697Snon	{
217979697Snon		scsi_low_reset_nexus_lun(slp, li, fdone);
218079697Snon		li->li_state = SCSI_LOW_LUN_SLEEP;
218179697Snon		li->li_maxnqio = 0;
218279697Snon	}
218379697Snon
218479697Snon	ti->ti_disc = 0;
218579697Snon	ti->ti_setup_msg = 0;
218679697Snon	ti->ti_setup_msg_done = 0;
218779697Snon
218879697Snon	ti->ti_osynch.offset = ti->ti_osynch.period = 0;
218979697Snon	ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
219079697Snon
219179697Snon	ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
219279697Snon	ti->ti_flags_valid &= ~SCSI_LOW_TARG_FLAGS_DISK_VALID;
219379697Snon
219479697Snon	if (slp->sl_funcs->scsi_low_targ_init != NULL)
219579697Snon	{
219679697Snon		((*slp->sl_funcs->scsi_low_targ_init)
219779697Snon			(slp, ti, SCSI_LOW_INFO_REVOKE));
219879697Snon	}
219979697Snon	scsi_low_calcf_target(ti);
220079697Snon
220179697Snon	for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
220279697Snon	     li = LIST_NEXT(li, lun_chain))
220379697Snon	{
220479697Snon		li->li_flags = 0;
220579697Snon
220679697Snon		li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
220779697Snon		li->li_flags_valid &= ~SCSI_LOW_LUN_FLAGS_DISK_VALID;
220879697Snon
220979697Snon		if (slp->sl_funcs->scsi_low_lun_init != NULL)
221079697Snon		{
221179697Snon			((*slp->sl_funcs->scsi_low_lun_init)
221279697Snon				(slp, ti, li, SCSI_LOW_INFO_REVOKE));
221379697Snon		}
221479697Snon		scsi_low_calcf_lun(li);
221579697Snon	}
221667468Snon}
221767468Snon
221867468Snonstatic void
221967468Snonscsi_low_reset_nexus(slp, fdone)
222067468Snon	struct scsi_low_softc *slp;
222167468Snon	int fdone;
222267468Snon{
222367468Snon	struct targ_info *ti;
222479697Snon	struct slccb *cb, *topcb;
222567468Snon
222679697Snon	if ((cb = slp->sl_Qnexus) != NULL)
222767468Snon	{
222879697Snon		topcb = scsi_low_revoke_ccb(slp, cb, fdone);
222967468Snon	}
223079697Snon	else
223179697Snon	{
223279697Snon		topcb = NULL;
223379697Snon	}
223467468Snon
223579697Snon	for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
223679697Snon	     ti = TAILQ_NEXT(ti, ti_chain))
223767468Snon	{
223879697Snon		scsi_low_reset_nexus_target(slp, ti, fdone);
223979697Snon		scsi_low_bus_release(slp, ti);
224067468Snon		scsi_low_init_msgsys(slp, ti);
224167468Snon	}
224267468Snon
224379697Snon	if (topcb != NULL)
224479697Snon	{
224579697Snon		topcb->ccb_flags |= CCB_STARTQ;
224679697Snon		TAILQ_INSERT_HEAD(&slp->sl_start, topcb, ccb_chain);
224779697Snon	}
224879697Snon
224979697Snon	slp->sl_disc = 0;
225079697Snon	slp->sl_retry_sel = 0;
225167468Snon	slp->sl_flags &= ~HW_PDMASTART;
225267468Snon}
225367468Snon
225467468Snon/* misc */
225567468Snonstatic int tw_pos;
225667468Snonstatic char tw_chars[] = "|/-\\";
225779697Snon#define	TWIDDLEWAIT		10000
225867468Snon
225967468Snonstatic void
226067468Snonscsi_low_twiddle_wait(void)
226167468Snon{
226267468Snon
226367468Snon	cnputc('\b');
226467468Snon	cnputc(tw_chars[tw_pos++]);
226567468Snon	tw_pos %= (sizeof(tw_chars) - 1);
2266240172Sjhb	DELAY(TWIDDLEWAIT);
226767468Snon}
226867468Snon
226967468Snonvoid
227067468Snonscsi_low_bus_reset(slp)
227167468Snon	struct scsi_low_softc *slp;
227267468Snon{
227367468Snon	int i;
227467468Snon
227567468Snon	(*slp->sl_funcs->scsi_low_bus_reset) (slp);
227667468Snon
2277240325Sjhb	device_printf(slp->sl_dev, "try to reset scsi bus  ");
227867468Snon	for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++)
227967468Snon		scsi_low_twiddle_wait();
228067468Snon	cnputc('\b');
228167468Snon	printf("\n");
228267468Snon}
228367468Snon
228467468Snonint
228567468Snonscsi_low_restart(slp, flags, s)
228667468Snon	struct scsi_low_softc *slp;
228767468Snon	int flags;
228867468Snon	u_char *s;
228967468Snon{
229067468Snon	int error;
229167468Snon
229267468Snon	if (s != NULL)
2293240325Sjhb		device_printf(slp->sl_dev, "scsi bus restart. reason: %s\n", s);
229467468Snon
229567468Snon	if ((error = scsi_low_init(slp, flags)) != 0)
229667468Snon		return error;
229767468Snon
229867468Snon	scsi_low_start(slp);
229967468Snon	return 0;
230067468Snon}
230167468Snon
230267468Snon/**************************************************************
230367468Snon * disconnect and reselect
230467468Snon **************************************************************/
230567468Snon#define	MSGCMD_LUN(msg)	(msg & 0x07)
230667468Snon
230767468Snonstatic struct slccb *
230867468Snonscsi_low_establish_ccb(ti, li, tag)
230967468Snon	struct targ_info *ti;
231067468Snon	struct lun_info *li;
231167468Snon	scsi_low_tag_t tag;
231267468Snon{
231367468Snon	struct scsi_low_softc *slp = ti->ti_sc;
231467468Snon	struct slccb *cb;
231567468Snon
231679697Snon	if (li == NULL)
231779697Snon		return NULL;
231879697Snon
231979697Snon	cb = TAILQ_FIRST(&li->li_discq);
232071999Sphk	for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain))
232179697Snon		if (cb->ccb_tag == tag)
232267468Snon			goto found;
232367468Snon	return cb;
232467468Snon
232567468Snon	/*
232667468Snon	 * establish our ccb nexus
232767468Snon	 */
232867468Snonfound:
232979697Snon#ifdef	SCSI_LOW_DEBUG
233079697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
233179697Snon	{
2332240325Sjhb		device_printf(slp->sl_dev, "nexus(0x%lx) abort check start\n",
2333240325Sjhb		    (u_long) cb);
233479697Snon		cb->ccb_flags |= (CCB_NORETRY | CCB_SILENT);
233579697Snon		scsi_low_revoke_ccb(slp, cb, 1);
233679697Snon		return NULL;
233779697Snon	}
233867468Snon
233979697Snon	if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id) != 0)
234079697Snon	{
234179697Snon		if (cb->ccb_omsgoutflag == 0)
234279697Snon			scsi_low_ccb_message_assert(cb, SCSI_LOW_MSG_NOOP);
234379697Snon	}
234479697Snon#endif	/* SCSI_LOW_DEBUG */
234579697Snon
234679697Snon	TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
234779697Snon	cb->ccb_flags &= ~CCB_DISCQ;
234879697Snon	slp->sl_Qnexus = cb;
234979697Snon
235067468Snon	slp->sl_scp = cb->ccb_sscp;
235167468Snon	slp->sl_error |= cb->ccb_error;
235267468Snon
235367468Snon	slp->sl_disc --;
235479697Snon	ti->ti_disc --;
235567468Snon	li->li_disc --;
235667468Snon
235767468Snon	/* inform "ccb nexus established" to the host driver */
235879697Snon	(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
235979697Snon
236079697Snon	/* check msg */
236179697Snon	if (cb->ccb_msgoutflag != 0)
236279697Snon	{
236379697Snon		scsi_low_ccb_message_exec(slp, cb);
236479697Snon	}
236579697Snon
236667468Snon	return cb;
236767468Snon}
236867468Snon
236967468Snonstruct targ_info *
237067468Snonscsi_low_reselected(slp, targ)
237167468Snon	struct scsi_low_softc *slp;
237267468Snon	u_int targ;
237367468Snon{
237467468Snon	struct targ_info *ti;
237579697Snon	struct slccb *cb;
237667468Snon	u_char *s;
237767468Snon
237867468Snon	/*
237967468Snon	 * Check select vs reselected collision.
238067468Snon	 */
238167468Snon
238279697Snon	if ((cb = slp->sl_selid) != NULL)
238367468Snon	{
238479697Snon		scsi_low_arbit_fail(slp, cb);
238567468Snon#ifdef	SCSI_LOW_STATICS
238667468Snon		scsi_low_statics.nexus_conflict ++;
238767468Snon#endif	/* SCSI_LOW_STATICS */
238867468Snon	}
238979697Snon
239079697Snon	/*
239179697Snon	 * Check if no current active nexus.
239279697Snon	 */
239379697Snon	if (slp->sl_Tnexus != NULL)
239467468Snon	{
239567468Snon		s = "host busy";
239667468Snon		goto world_restart;
239767468Snon	}
239867468Snon
239967468Snon	/*
240067468Snon	 * Check a valid target id asserted ?
240167468Snon	 */
240267468Snon	if (targ >= slp->sl_ntargs || targ == slp->sl_hostid)
240367468Snon	{
240467468Snon		s = "scsi id illegal";
240567468Snon		goto world_restart;
240667468Snon	}
240767468Snon
240867468Snon	/*
240967468Snon	 * Check the target scsi status.
241067468Snon	 */
241167468Snon	ti = slp->sl_ti[targ];
241279697Snon	if (ti->ti_phase != PH_DISC && ti->ti_phase != PH_NULL)
241367468Snon	{
241467468Snon		s = "phase mismatch";
241567468Snon		goto world_restart;
241667468Snon	}
241767468Snon
241867468Snon	/*
241979697Snon	 * Setup init msgsys
242067468Snon	 */
242167468Snon	slp->sl_error = 0;
242267468Snon	scsi_low_init_msgsys(slp, ti);
242367468Snon
242467468Snon	/*
242567468Snon	 * Establish our target nexus
242667468Snon	 */
242767468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_RESEL);
242879697Snon	slp->sl_Tnexus = ti;
242967468Snon#ifdef	SCSI_LOW_STATICS
243067468Snon	scsi_low_statics.nexus_reselected ++;
243167468Snon#endif	/* SCSI_LOW_STATICS */
243267468Snon	return ti;
243367468Snon
243467468Snonworld_restart:
2435240325Sjhb	device_printf(slp->sl_dev, "reselect(%x:unknown) %s\n", targ, s);
243667468Snon	scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
243767468Snon		         "reselect: scsi world confused");
243867468Snon	return NULL;
243967468Snon}
244067468Snon
244167468Snon/**************************************************************
244267468Snon * cmd out pointer setup
244367468Snon **************************************************************/
244467468Snonint
244567468Snonscsi_low_cmd(slp, ti)
244667468Snon	struct scsi_low_softc *slp;
244767468Snon	struct targ_info *ti;
244867468Snon{
244979697Snon	struct slccb *cb = slp->sl_Qnexus;
245067468Snon
245179697Snon	slp->sl_ph_count ++;
245267468Snon	if (cb == NULL)
245367468Snon	{
245467468Snon		/*
245579697Snon		 * no ccb, abort!
245667468Snon		 */
245767468Snon		slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd;
245867468Snon		slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd);
245967468Snon		slp->sl_scp.scp_datalen = 0;
246067468Snon		slp->sl_scp.scp_direction = SCSI_LOW_READ;
246179697Snon		slp->sl_error |= FATALIO;
246279697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
246379697Snon		SCSI_LOW_INFO(slp, ti, "CMDOUT: ccb nexus not found");
246479697Snon		return EINVAL;
246567468Snon	}
246679697Snon	else
246767468Snon	{
246879697Snon#ifdef	SCSI_LOW_DEBUG
246979697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_CMDLNK_CHECK, ti->ti_id))
247079697Snon		{
247179697Snon			scsi_low_test_cmdlnk(slp, cb);
247279697Snon		}
247379697Snon#endif	/* SCSI_LOW_DEBUG */
247467468Snon	}
247567468Snon	return 0;
247667468Snon}
247767468Snon
247867468Snon/**************************************************************
247967468Snon * data out pointer setup
248067468Snon **************************************************************/
248167468Snonint
248267468Snonscsi_low_data(slp, ti, bp, direction)
248367468Snon	struct scsi_low_softc *slp;
248467468Snon	struct targ_info *ti;
248567468Snon	struct buf **bp;
248667468Snon	int direction;
248767468Snon{
248879697Snon	struct slccb *cb = slp->sl_Qnexus;
248967468Snon
249079697Snon	if (cb != NULL && direction == cb->ccb_sscp.scp_direction)
249167468Snon	{
249279697Snon		*bp = cb->bp;
249379697Snon		return 0;
249467468Snon	}
249567468Snon
249679697Snon	slp->sl_error |= (FATALIO | PDMAERR);
249779697Snon	slp->sl_scp.scp_datalen = 0;
249879697Snon	slp->sl_scp.scp_direction = direction;
249979697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
250079697Snon	if (ti->ti_ophase != ti->ti_phase)
250167468Snon	{
250279697Snon		char *s;
250379697Snon
250479697Snon		if (cb == NULL)
250579697Snon			s = "DATA PHASE: ccb nexus not found";
250679697Snon		else
250779697Snon			s = "DATA PHASE: xfer direction mismatch";
250879697Snon		SCSI_LOW_INFO(slp, ti, s);
250967468Snon	}
251067468Snon
251179697Snon	*bp = NULL;
251279697Snon	return EINVAL;
251367468Snon}
251467468Snon
251567468Snon/**************************************************************
251667468Snon * MSG_SYS
251767468Snon **************************************************************/
251867468Snon#define	MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;}
251967468Snon#define	MSGIN_PERIOD(ti) ((ti)->ti_msgin[3])
252067468Snon#define	MSGIN_OFFSET(ti) ((ti)->ti_msgin[4])
252179697Snon#define	MSGIN_WIDTHP(ti) ((ti)->ti_msgin[3])
252267468Snon#define	MSGIN_DATA_LAST	0x30
252367468Snon
252492770Salfredstatic int scsi_low_errfunc_synch(struct scsi_low_softc *, u_int);
252592770Salfredstatic int scsi_low_errfunc_wide(struct scsi_low_softc *, u_int);
252692770Salfredstatic int scsi_low_errfunc_identify(struct scsi_low_softc *, u_int);
252792770Salfredstatic int scsi_low_errfunc_qtag(struct scsi_low_softc *, u_int);
252867468Snon
252992770Salfredstatic int scsi_low_msgfunc_synch(struct scsi_low_softc *);
253092770Salfredstatic int scsi_low_msgfunc_wide(struct scsi_low_softc *);
253192770Salfredstatic int scsi_low_msgfunc_identify(struct scsi_low_softc *);
253292770Salfredstatic int scsi_low_msgfunc_abort(struct scsi_low_softc *);
253392770Salfredstatic int scsi_low_msgfunc_qabort(struct scsi_low_softc *);
253492770Salfredstatic int scsi_low_msgfunc_qtag(struct scsi_low_softc *);
253592770Salfredstatic int scsi_low_msgfunc_reset(struct scsi_low_softc *);
253667468Snon
253767468Snonstruct scsi_low_msgout_data {
253867468Snon	u_int	md_flags;
253967468Snon	u_int8_t md_msg;
254092770Salfred	int (*md_msgfunc)(struct scsi_low_softc *);
254192770Salfred	int (*md_errfunc)(struct scsi_low_softc *, u_int);
254279697Snon#define	MSG_RELEASE_ATN	0x0001
254379697Snon	u_int md_condition;
254467468Snon};
254567468Snon
254667468Snonstruct scsi_low_msgout_data scsi_low_msgout_data[] = {
254779697Snon/* 0 */	{SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_reset, NULL, MSG_RELEASE_ATN},
254879697Snon/* 1 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL, MSG_RELEASE_ATN},
254979697Snon/* 2 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL, MSG_RELEASE_ATN},
255079697Snon/* 3 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL, MSG_RELEASE_ATN},
255179697Snon/* 4 */ {SCSI_LOW_MSG_IDENTIFY, MSG_IDENTIFY, scsi_low_msgfunc_identify, scsi_low_errfunc_identify, 0},
255279697Snon/* 5 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
255379697Snon/* 6 */ {SCSI_LOW_MSG_TERMIO, MSG_TERM_IO, NULL, NULL, MSG_RELEASE_ATN},
255479697Snon/* 7 */ {SCSI_LOW_MSG_SIMPLE_QTAG,  MSG_SIMPLE_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
255579697Snon/* 8 */ {SCSI_LOW_MSG_ORDERED_QTAG, MSG_ORDERED_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
255679697Snon/* 9 */{SCSI_LOW_MSG_HEAD_QTAG,  MSG_HEAD_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
255779697Snon/* 10 */ {SCSI_LOW_MSG_ABORT_QTAG, MSG_ABORT_QTAG, scsi_low_msgfunc_qabort, NULL,  MSG_RELEASE_ATN},
255879697Snon/* 11 */ {SCSI_LOW_MSG_CLEAR_QTAG, MSG_CLEAR_QTAG, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
255979697Snon/* 12 */{SCSI_LOW_MSG_WIDE, MSG_EXTEND, scsi_low_msgfunc_wide, scsi_low_errfunc_wide, MSG_RELEASE_ATN},
256079697Snon/* 13 */{SCSI_LOW_MSG_SYNCH, MSG_EXTEND, scsi_low_msgfunc_synch, scsi_low_errfunc_synch, MSG_RELEASE_ATN},
256179697Snon/* 14 */{SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL, MSG_RELEASE_ATN},
256279697Snon/* 15 */{SCSI_LOW_MSG_ALL, 0},
256367468Snon};
256467468Snon
256592770Salfredstatic int scsi_low_msginfunc_ext(struct scsi_low_softc *);
256692770Salfredstatic int scsi_low_synch(struct scsi_low_softc *);
256792770Salfredstatic int scsi_low_wide(struct scsi_low_softc *);
256892770Salfredstatic int scsi_low_msginfunc_msg_reject(struct scsi_low_softc *);
256992770Salfredstatic int scsi_low_msginfunc_rejop(struct scsi_low_softc *);
257092770Salfredstatic int scsi_low_msginfunc_rp(struct scsi_low_softc *);
257192770Salfredstatic int scsi_low_msginfunc_sdp(struct scsi_low_softc *);
257292770Salfredstatic int scsi_low_msginfunc_disc(struct scsi_low_softc *);
257392770Salfredstatic int scsi_low_msginfunc_cc(struct scsi_low_softc *);
257492770Salfredstatic int scsi_low_msginfunc_lcc(struct scsi_low_softc *);
257592770Salfredstatic int scsi_low_msginfunc_parity(struct scsi_low_softc *);
257692770Salfredstatic int scsi_low_msginfunc_noop(struct scsi_low_softc *);
257792770Salfredstatic int scsi_low_msginfunc_simple_qtag(struct scsi_low_softc *);
257892770Salfredstatic int scsi_low_msginfunc_i_wide_residue(struct scsi_low_softc *);
257967468Snon
258067468Snonstruct scsi_low_msgin_data {
258167468Snon	u_int md_len;
258292770Salfred	int (*md_msgfunc)(struct scsi_low_softc *);
258367468Snon};
258467468Snon
258567468Snonstruct scsi_low_msgin_data scsi_low_msgin_data[] = {
258667468Snon/* 0 */	{1,	scsi_low_msginfunc_cc},
258767468Snon/* 1 */ {2,	scsi_low_msginfunc_ext},
258867468Snon/* 2 */ {1,	scsi_low_msginfunc_sdp},
258979697Snon/* 3 */ {1,	scsi_low_msginfunc_rp},
259067468Snon/* 4 */ {1,	scsi_low_msginfunc_disc},
259167468Snon/* 5 */ {1,	scsi_low_msginfunc_rejop},
259267468Snon/* 6 */ {1,	scsi_low_msginfunc_rejop},
259367468Snon/* 7 */ {1,	scsi_low_msginfunc_msg_reject},
259467468Snon/* 8 */ {1,	scsi_low_msginfunc_noop},
259567468Snon/* 9 */ {1,	scsi_low_msginfunc_parity},
259679697Snon/* a */ {1,	scsi_low_msginfunc_lcc},
259779697Snon/* b */ {1,	scsi_low_msginfunc_lcc},
259867468Snon/* c */ {1,	scsi_low_msginfunc_rejop},
259967468Snon/* d */ {2,	scsi_low_msginfunc_rejop},
260067468Snon/* e */ {1,	scsi_low_msginfunc_rejop},
260167468Snon/* f */ {1,	scsi_low_msginfunc_rejop},
260267468Snon/* 0x10 */ {1,	scsi_low_msginfunc_rejop},
260367468Snon/* 0x11 */ {1,	scsi_low_msginfunc_rejop},
260467468Snon/* 0x12 */ {1,	scsi_low_msginfunc_rejop},
260567468Snon/* 0x13 */ {1,	scsi_low_msginfunc_rejop},
260667468Snon/* 0x14 */ {1,	scsi_low_msginfunc_rejop},
260767468Snon/* 0x15 */ {1,	scsi_low_msginfunc_rejop},
260867468Snon/* 0x16 */ {1,	scsi_low_msginfunc_rejop},
260967468Snon/* 0x17 */ {1,	scsi_low_msginfunc_rejop},
261067468Snon/* 0x18 */ {1,	scsi_low_msginfunc_rejop},
261167468Snon/* 0x19 */ {1,	scsi_low_msginfunc_rejop},
261267468Snon/* 0x1a */ {1,	scsi_low_msginfunc_rejop},
261367468Snon/* 0x1b */ {1,	scsi_low_msginfunc_rejop},
261467468Snon/* 0x1c */ {1,	scsi_low_msginfunc_rejop},
261567468Snon/* 0x1d */ {1,	scsi_low_msginfunc_rejop},
261667468Snon/* 0x1e */ {1,	scsi_low_msginfunc_rejop},
261767468Snon/* 0x1f */ {1,	scsi_low_msginfunc_rejop},
261879697Snon/* 0x20 */ {2,	scsi_low_msginfunc_simple_qtag},
261967468Snon/* 0x21 */ {2,	scsi_low_msginfunc_rejop},
262067468Snon/* 0x22 */ {2,	scsi_low_msginfunc_rejop},
262179697Snon/* 0x23 */ {2,	scsi_low_msginfunc_i_wide_residue},
262267468Snon/* 0x24 */ {2,	scsi_low_msginfunc_rejop},
262367468Snon/* 0x25 */ {2,	scsi_low_msginfunc_rejop},
262467468Snon/* 0x26 */ {2,	scsi_low_msginfunc_rejop},
262567468Snon/* 0x27 */ {2,	scsi_low_msginfunc_rejop},
262667468Snon/* 0x28 */ {2,	scsi_low_msginfunc_rejop},
262767468Snon/* 0x29 */ {2,	scsi_low_msginfunc_rejop},
262867468Snon/* 0x2a */ {2,	scsi_low_msginfunc_rejop},
262967468Snon/* 0x2b */ {2,	scsi_low_msginfunc_rejop},
263067468Snon/* 0x2c */ {2,	scsi_low_msginfunc_rejop},
263167468Snon/* 0x2d */ {2,	scsi_low_msginfunc_rejop},
263267468Snon/* 0x2e */ {2,	scsi_low_msginfunc_rejop},
263367468Snon/* 0x2f */ {2,	scsi_low_msginfunc_rejop},
263467468Snon/* 0x30 */ {1,	scsi_low_msginfunc_rejop}	/* default rej op */
263567468Snon};
263667468Snon
263767468Snon/**************************************************************
263867468Snon * msgout
263967468Snon **************************************************************/
264067468Snonstatic int
264179697Snonscsi_low_msgfunc_synch(slp)
264279697Snon	struct scsi_low_softc *slp;
264367468Snon{
264479697Snon	struct targ_info *ti = slp->sl_Tnexus;
264567468Snon	int ptr = ti->ti_msgoutlen;
264667468Snon
264767468Snon	ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN;
264867468Snon	ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE;
264973025Snon	ti->ti_msgoutstr[ptr + 3] = ti->ti_maxsynch.period;
265073025Snon	ti->ti_msgoutstr[ptr + 4] = ti->ti_maxsynch.offset;
265167468Snon	return MSG_EXTEND_SYNCHLEN + 2;
265267468Snon}
265367468Snon
265467468Snonstatic int
265579697Snonscsi_low_msgfunc_wide(slp)
265679697Snon	struct scsi_low_softc *slp;
265767468Snon{
265879697Snon	struct targ_info *ti = slp->sl_Tnexus;
265967468Snon	int ptr = ti->ti_msgoutlen;
266067468Snon
266167468Snon	ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN;
266267468Snon	ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE;
266373025Snon	ti->ti_msgoutstr[ptr + 3] = ti->ti_width;
266467468Snon	return MSG_EXTEND_WIDELEN + 2;
266567468Snon}
266667468Snon
266767468Snonstatic int
266879697Snonscsi_low_msgfunc_identify(slp)
266979697Snon	struct scsi_low_softc *slp;
267067468Snon{
267179697Snon	struct targ_info *ti = slp->sl_Tnexus;
267279697Snon	struct lun_info *li = slp->sl_Lnexus;
267379697Snon	struct slccb *cb = slp->sl_Qnexus;
267479697Snon	int ptr = ti->ti_msgoutlen;
267579697Snon	u_int8_t msg;
267667468Snon
267779697Snon	msg = MSG_IDENTIFY;
267879697Snon	if (cb == NULL)
267967468Snon	{
268079697Snon		slp->sl_error |= FATALIO;
268179697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
268279697Snon		SCSI_LOW_INFO(slp, ti, "MSGOUT: nexus unknown");
268367468Snon	}
268467468Snon	else
268567468Snon	{
268679697Snon		if (scsi_low_is_disconnect_ok(cb) != 0)
268779697Snon			msg |= (MSG_IDENTIFY_DISCPRIV | li->li_lun);
268879697Snon		else
268979697Snon			msg |= li->li_lun;
269079697Snon
269179697Snon		if (ti->ti_phase == PH_MSGOUT)
269279697Snon		{
269379697Snon			(*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
269479697Snon			if (cb->ccb_tag == SCSI_LOW_UNKTAG)
269579697Snon			{
269679697Snon				(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
269779697Snon			}
269879697Snon		}
269967468Snon	}
270079697Snon	ti->ti_msgoutstr[ptr + 0] = msg;
270167468Snon	return 1;
270267468Snon}
270367468Snon
270467468Snonstatic int
270579697Snonscsi_low_msgfunc_abort(slp)
270679697Snon	struct scsi_low_softc *slp;
270767468Snon{
270867468Snon
270979697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_ABORT);
271079697Snon	return 1;
271179697Snon}
271279697Snon
271379697Snonstatic int
271479697Snonscsi_low_msgfunc_qabort(slp)
271579697Snon	struct scsi_low_softc *slp;
271679697Snon{
271779697Snon
271879697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_TERM);
271979697Snon	return 1;
272079697Snon}
272179697Snon
272279697Snonstatic int
272379697Snonscsi_low_msgfunc_reset(slp)
272479697Snon	struct scsi_low_softc *slp;
272579697Snon{
272679697Snon
272779697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_RESET);
272879697Snon	return 1;
272979697Snon}
273079697Snon
273179697Snonstatic int
273279697Snonscsi_low_msgfunc_qtag(slp)
273379697Snon	struct scsi_low_softc *slp;
273479697Snon{
273579697Snon	struct targ_info *ti = slp->sl_Tnexus;
273679697Snon	struct slccb *cb = slp->sl_Qnexus;
273779697Snon	int ptr = ti->ti_msgoutlen;
273879697Snon
273979697Snon	if (cb == NULL || cb->ccb_tag == SCSI_LOW_UNKTAG)
274067468Snon	{
274167468Snon		ti->ti_msgoutstr[ptr + 0] = MSG_NOOP;
274267468Snon		return 1;
274367468Snon	}
274467468Snon	else
274567468Snon	{
274679697Snon		ti->ti_msgoutstr[ptr + 1] = (u_int8_t) cb->ccb_tag;
274779697Snon		if (ti->ti_phase == PH_MSGOUT)
274879697Snon		{
274979697Snon			(*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
275079697Snon		}
275167468Snon	}
275279697Snon	return 2;
275367468Snon}
275467468Snon
275567468Snon/*
275667468Snon * The following functions are called when targets give unexpected
275767468Snon * responces in msgin (after msgout).
275867468Snon */
275967468Snonstatic int
276079697Snonscsi_low_errfunc_identify(slp, msgflags)
276179697Snon	struct scsi_low_softc *slp;
276267468Snon	u_int msgflags;
276367468Snon{
276467468Snon
276579697Snon	if (slp->sl_Lnexus != NULL)
276679697Snon	{
276779697Snon	        slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_DISC;
276879697Snon		scsi_low_calcf_lun(slp->sl_Lnexus);
276979697Snon	}
277067468Snon	return 0;
277167468Snon}
277267468Snon
277367468Snonstatic int
277479697Snonscsi_low_errfunc_synch(slp, msgflags)
277579697Snon	struct scsi_low_softc *slp;
277667468Snon	u_int msgflags;
277767468Snon{
277879697Snon	struct targ_info *ti = slp->sl_Tnexus;
277967468Snon
278067468Snon	MSGIN_PERIOD(ti) = 0;
278167468Snon	MSGIN_OFFSET(ti) = 0;
278279697Snon	scsi_low_synch(slp);
278367468Snon	return 0;
278467468Snon}
278567468Snon
278667468Snonstatic int
278779697Snonscsi_low_errfunc_wide(slp, msgflags)
278879697Snon	struct scsi_low_softc *slp;
278967468Snon	u_int msgflags;
279067468Snon{
279179697Snon	struct targ_info *ti = slp->sl_Tnexus;
279279697Snon
279379697Snon	MSGIN_WIDTHP(ti) = 0;
279479697Snon	scsi_low_wide(slp);
279567468Snon	return 0;
279667468Snon}
279767468Snon
279879697Snonstatic int
279979697Snonscsi_low_errfunc_qtag(slp, msgflags)
280079697Snon	struct scsi_low_softc *slp;
280179697Snon	u_int msgflags;
280279697Snon{
280379697Snon
280479697Snon	if ((msgflags & SCSI_LOW_MSG_REJECT) != 0)
280579697Snon	{
280679697Snon		if (slp->sl_Qnexus != NULL)
280779697Snon		{
280879697Snon			scsi_low_deactivate_qtag(slp->sl_Qnexus);
280979697Snon		}
281079697Snon		if (slp->sl_Lnexus != NULL)
281179697Snon		{
281279697Snon			slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_QTAG;
281379697Snon			scsi_low_calcf_lun(slp->sl_Lnexus);
281479697Snon		}
2815240325Sjhb		device_printf(slp->sl_dev, "scsi_low: qtag msg rejected\n");
281679697Snon	}
281779697Snon	return 0;
281879697Snon}
281979697Snon
282079697Snon
282167468Snonint
282279697Snonscsi_low_msgout(slp, ti, fl)
282367468Snon	struct scsi_low_softc *slp;
282467468Snon	struct targ_info *ti;
282579697Snon	u_int fl;
282667468Snon{
282767468Snon	struct scsi_low_msgout_data *mdp;
282867468Snon	int len = 0;
282967468Snon
283079697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
283179697Snon	if (ti != slp->sl_Tnexus)
283279697Snon	{
283379697Snon		scsi_low_print(slp, NULL);
283479697Snon		panic("scsi_low_msgout: Target nexus inconsistent");
283579697Snon	}
283679697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
283779697Snon
283879697Snon	slp->sl_ph_count ++;
283979697Snon	if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
284079697Snon	{
2841240325Sjhb		device_printf(slp->sl_dev, "too many phase changes\n");
284279697Snon		slp->sl_error |= FATALIO;
284379697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
284479697Snon	}
284579697Snon
284667468Snon	/* STEP I.
284767468Snon	 * Scsi phase changes.
284867468Snon	 * Previously msgs asserted are accepted by our target or
284967468Snon	 * processed by scsi_low_msgin.
285067468Snon	 * Thus clear all saved informations.
285167468Snon	 */
285279697Snon	if ((fl & SCSI_LOW_MSGOUT_INIT) != 0)
285367468Snon	{
285467468Snon		ti->ti_omsgflags = 0;
285567468Snon		ti->ti_emsgflags = 0;
285667468Snon	}
285779697Snon	else if (slp->sl_atten == 0)
285879697Snon	{
285967468Snon	/* STEP II.
286067468Snon	 * We did not assert attention, however still our target required
286167468Snon	 * msgs. Resend previous msgs.
286267468Snon	 */
286367468Snon		ti->ti_msgflags |= ti->ti_omsgflags;
286479697Snon		ti->ti_omsgflags = 0;
286567468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
2866240325Sjhb		device_printf(slp->sl_dev, "scsi_low_msgout: retry msgout\n");
286767468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
286867468Snon	}
286967468Snon
287067468Snon	/* STEP III.
287179697Snon	 * We have no msgs. send MSG_NOOP (OK?)
287267468Snon	 */
287379697Snon	if (scsi_low_is_msgout_continue(ti, 0) == 0)
287467468Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0);
287567468Snon
287667468Snon	/* STEP IV.
287767468Snon	 * Process all msgs
287867468Snon	 */
287967468Snon	ti->ti_msgoutlen = 0;
288079697Snon	slp->sl_clear_atten = 0;
288167468Snon	mdp = &scsi_low_msgout_data[0];
288267468Snon	for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
288367468Snon	{
288467468Snon		if ((ti->ti_msgflags & mdp->md_flags) != 0)
288567468Snon		{
288667468Snon			ti->ti_omsgflags |= mdp->md_flags;
288767468Snon			ti->ti_msgflags &= ~mdp->md_flags;
288867468Snon			ti->ti_emsgflags = mdp->md_flags;
288967468Snon
289067468Snon			ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg;
289167468Snon			if (mdp->md_msgfunc != NULL)
289279697Snon				len = (*mdp->md_msgfunc) (slp);
289367468Snon			else
289467468Snon				len = 1;
289567468Snon
289679697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
289779697Snon			scsi_low_msg_log_write(&ti->ti_log_msgout,
289879697Snon			       &ti->ti_msgoutstr[ti->ti_msgoutlen], len);
289979697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
290079697Snon
290167468Snon			ti->ti_msgoutlen += len;
290279697Snon			if ((mdp->md_condition & MSG_RELEASE_ATN) != 0)
290379697Snon			{
290479697Snon				slp->sl_clear_atten = 1;
290579697Snon				break;
290679697Snon			}
290779697Snon
290879697Snon			if ((fl & SCSI_LOW_MSGOUT_UNIFY) == 0 ||
290967468Snon			    ti->ti_msgflags == 0)
291067468Snon				break;
291179697Snon
291267468Snon			if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5)
291367468Snon				break;
291467468Snon		}
291567468Snon	}
291667468Snon
291779697Snon	if (scsi_low_is_msgout_continue(ti, 0) == 0)
291879697Snon		slp->sl_clear_atten = 1;
291967468Snon
292067468Snon	return ti->ti_msgoutlen;
292167468Snon}
292267468Snon
292367468Snon/**************************************************************
292467468Snon * msgin
292567468Snon **************************************************************/
292667468Snonstatic int
292779697Snonscsi_low_msginfunc_noop(slp)
292879697Snon	struct scsi_low_softc *slp;
292967468Snon{
293067468Snon
293167468Snon	return 0;
293267468Snon}
293367468Snon
293467468Snonstatic int
293579697Snonscsi_low_msginfunc_rejop(slp)
293679697Snon	struct scsi_low_softc *slp;
293767468Snon{
293879697Snon	struct targ_info *ti = slp->sl_Tnexus;
293967468Snon	u_int8_t msg = ti->ti_msgin[0];
294067468Snon
2941240325Sjhb	device_printf(slp->sl_dev, "MSGIN: msg 0x%x rejected\n", (u_int) msg);
294267468Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
294367468Snon	return 0;
294467468Snon}
294567468Snon
294667468Snonstatic int
294779697Snonscsi_low_msginfunc_cc(slp)
294879697Snon	struct scsi_low_softc *slp;
294967468Snon{
295079697Snon	struct lun_info *li;
295167468Snon
295267468Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC);
295379697Snon
295479697Snon	/* validate status */
295579697Snon	if (slp->sl_Qnexus == NULL)
295679697Snon		return ENOENT;
295779697Snon
295879697Snon	slp->sl_Qnexus->ccb_sscp.scp_status = slp->sl_scp.scp_status;
295979697Snon 	li = slp->sl_Lnexus;
296079697Snon	switch (slp->sl_scp.scp_status)
296179697Snon	{
296279697Snon	case ST_GOOD:
296379697Snon		li->li_maxnqio = li->li_maxnexus;
296479697Snon		break;
296579697Snon
296679697Snon	case ST_CHKCOND:
296779697Snon		li->li_maxnqio = 0;
296879697Snon		if (li->li_qflags & SCSI_LOW_QFLAG_CA_QCLEAR)
296979697Snon			scsi_low_reset_nexus_lun(slp, li, 0);
297079697Snon		break;
297179697Snon
297279697Snon	case ST_BUSY:
297379697Snon		li->li_maxnqio = 0;
297479697Snon		break;
297579697Snon
297679697Snon	case ST_QUEFULL:
297779697Snon		if (li->li_maxnexus >= li->li_nqio)
297879697Snon			li->li_maxnexus = li->li_nqio - 1;
297979697Snon		li->li_maxnqio = li->li_maxnexus;
298079697Snon		break;
298179697Snon
298279697Snon	case ST_INTERGOOD:
298379697Snon	case ST_INTERMET:
298479697Snon		slp->sl_error |= MSGERR;
298579697Snon		break;
298679697Snon
298779697Snon	default:
298879697Snon		break;
298979697Snon	}
299067468Snon	return 0;
299167468Snon}
299267468Snon
299367468Snonstatic int
299479697Snonscsi_low_msginfunc_lcc(slp)
299579697Snon	struct scsi_low_softc *slp;
299679697Snon{
299767468Snon	struct targ_info *ti;
299879697Snon	struct lun_info *li;
299979697Snon	struct slccb *ncb, *cb;
300079697Snon
300179697Snon	ti = slp->sl_Tnexus;
300279697Snon 	li = slp->sl_Lnexus;
300379697Snon	if ((cb = slp->sl_Qnexus) == NULL)
300479697Snon		goto bad;
300579697Snon
300679697Snon	cb->ccb_sscp.scp_status = slp->sl_scp.scp_status;
300779697Snon	switch (slp->sl_scp.scp_status)
300879697Snon	{
300979697Snon	case ST_INTERGOOD:
301079697Snon	case ST_INTERMET:
301179697Snon		li->li_maxnqio = li->li_maxnexus;
301279697Snon		break;
301379697Snon
301479697Snon	default:
301579697Snon		slp->sl_error |= MSGERR;
301679697Snon		break;
301779697Snon	}
301879697Snon
301979697Snon	if ((li->li_flags & SCSI_LOW_LINK) == 0)
302079697Snon		goto bad;
302179697Snon
302279697Snon	cb->ccb_error |= slp->sl_error;
302379697Snon	if (cb->ccb_error != 0)
302479697Snon		goto bad;
302579697Snon
302679697Snon	for (ncb = TAILQ_FIRST(&slp->sl_start); ncb != NULL;
302779697Snon	     ncb = TAILQ_NEXT(ncb, ccb_chain))
302879697Snon	{
302979697Snon		if (ncb->li == li)
303079697Snon			goto cmd_link_start;
303179697Snon	}
303279697Snon
303379697Snon
303479697Snonbad:
303579697Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_LCTERM);
303679697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
303779697Snon	return EIO;
303879697Snon
303979697Snoncmd_link_start:
304079697Snon	ncb->ccb_flags &= ~CCB_STARTQ;
304179697Snon	TAILQ_REMOVE(&slp->sl_start, ncb, ccb_chain);
304279697Snon
304379697Snon	scsi_low_dealloc_qtag(ncb);
304479697Snon	ncb->ccb_tag = cb->ccb_tag;
304579697Snon	ncb->ccb_otag = cb->ccb_otag;
304679697Snon	cb->ccb_tag = SCSI_LOW_UNKTAG;
304779697Snon	cb->ccb_otag = SCSI_LOW_UNKTAG;
304879697Snon	if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
3049240325Sjhb		panic("%s: linked ccb retried",
3050240325Sjhb		    device_get_nameunit(slp->sl_dev));
305179697Snon
305279697Snon	slp->sl_Qnexus = ncb;
305379697Snon	slp->sl_ph_count = 0;
305479697Snon
305579697Snon	ncb->ccb_error = 0;
305679697Snon	ncb->ccb_datalen = -1;
305779697Snon	ncb->ccb_scp.scp_status = ST_UNKNOWN;
305879697Snon	ncb->ccb_flags &= ~CCB_INTERNAL;
305979697Snon
306079697Snon	scsi_low_init_msgsys(slp, ti);
306179697Snon
3062274760Sjhb	scsi_low_ccb_setup_cam(slp, ncb);
306379697Snon
306479697Snon	if (ncb->ccb_tcmax < SCSI_LOW_MIN_TOUT)
306579697Snon		ncb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
306679697Snon	ncb->ccb_tc = ncb->ccb_tcmax;
306779697Snon
306879697Snon	/* setup saved scsi data pointer */
306979697Snon	ncb->ccb_sscp = ncb->ccb_scp;
307079697Snon	slp->sl_scp = ncb->ccb_sscp;
307179697Snon	slp->sl_error = ncb->ccb_error;
307279697Snon
307379697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
307479697Snon	scsi_low_msg_log_init(&ti->ti_log_msgin);
307579697Snon	scsi_low_msg_log_init(&ti->ti_log_msgout);
307679697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
307779697Snon	return EJUSTRETURN;
307879697Snon}
307979697Snon
308079697Snonstatic int
308179697Snonscsi_low_msginfunc_disc(slp)
308279697Snon	struct scsi_low_softc *slp;
308367468Snon{
308467468Snon
308567468Snon	SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC);
308667468Snon	return 0;
308767468Snon}
308867468Snon
308967468Snonstatic int
309079697Snonscsi_low_msginfunc_sdp(slp)
309179697Snon	struct scsi_low_softc *slp;
309267468Snon{
309379697Snon	struct slccb *cb = slp->sl_Qnexus;
309467468Snon
309579697Snon	if (cb != NULL)
309679697Snon	{
309779697Snon		cb->ccb_sscp.scp_datalen = slp->sl_scp.scp_datalen;
309879697Snon		cb->ccb_sscp.scp_data = slp->sl_scp.scp_data;
309979697Snon	}
310067468Snon	else
310179697Snon		scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
310267468Snon	return 0;
310367468Snon}
310467468Snon
310567468Snonstatic int
310679697Snonscsi_low_msginfunc_rp(slp)
310779697Snon	struct scsi_low_softc *slp;
310867468Snon{
310967468Snon
311079697Snon	if (slp->sl_Qnexus != NULL)
311179697Snon		slp->sl_scp = slp->sl_Qnexus->ccb_sscp;
311267468Snon	else
311379697Snon		scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
311467468Snon	return 0;
311567468Snon}
311667468Snon
311767468Snonstatic int
311879697Snonscsi_low_synch(slp)
311979697Snon	struct scsi_low_softc *slp;
312067468Snon{
312179697Snon	struct targ_info *ti = slp->sl_Tnexus;
312279697Snon	u_int period = 0, offset = 0, speed;
312367468Snon	u_char *s;
312467468Snon	int error;
312567468Snon
312679697Snon	if ((MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period &&
312779697Snon	     MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset) ||
312879697Snon	     MSGIN_OFFSET(ti) == 0)
312967468Snon	{
313067468Snon		if ((offset = MSGIN_OFFSET(ti)) != 0)
313167468Snon			period = MSGIN_PERIOD(ti);
313267468Snon		s = offset ? "synchronous" : "async";
313367468Snon	}
313467468Snon	else
313567468Snon	{
313667468Snon		/* XXX:
313767468Snon		 * Target seems to be brain damaged.
313867468Snon		 * Force async transfer.
313967468Snon		 */
314073025Snon		ti->ti_maxsynch.period = 0;
314173025Snon		ti->ti_maxsynch.offset = 0;
3142240325Sjhb		device_printf(slp->sl_dev,
3143240325Sjhb		    "target brain damaged. async transfer\n");
314467468Snon		return EINVAL;
314567468Snon	}
314667468Snon
314773025Snon	ti->ti_maxsynch.period = period;
314873025Snon	ti->ti_maxsynch.offset = offset;
314967468Snon
315067468Snon	error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH);
315167468Snon	if (error != 0)
315267468Snon	{
315367468Snon		/* XXX:
315467468Snon		 * Current period and offset are not acceptable
315567468Snon		 * for our adapter.
315667468Snon		 * The adapter changes max synch and max offset.
315767468Snon		 */
3158240325Sjhb		device_printf(slp->sl_dev,
3159240325Sjhb		    "synch neg failed. retry synch msg neg ...\n");
316067468Snon		return error;
316167468Snon	}
316267468Snon
316379697Snon	ti->ti_osynch = ti->ti_maxsynch;
316479697Snon	if (offset > 0)
316579697Snon	{
316679697Snon		ti->ti_setup_msg_done |= SCSI_LOW_MSG_SYNCH;
316779697Snon	}
316879697Snon
316967468Snon	/* inform data */
317079697Snon	if ((slp->sl_show_result & SHOW_SYNCH_NEG) != 0)
317167468Snon	{
317279697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
317379697Snon		struct slccb *cb = slp->sl_Qnexus;
317479697Snon
317579697Snon		if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
317679697Snon			return 0;
317779697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
317879697Snon
3179240325Sjhb		device_printf(slp->sl_dev,
3180240325Sjhb		    "(%d:*): <%s> offset %d period %dns ",
3181240325Sjhb		    ti->ti_id, s, offset, period * 4);
318279697Snon
318379697Snon		if (period != 0)
318479697Snon		{
318579697Snon			speed = 1000 * 10 / (period * 4);
318679697Snon			printf("%d.%d M/s", speed / 10, speed % 10);
318779697Snon		}
318879697Snon		printf("\n");
318967468Snon	}
319079697Snon	return 0;
319179697Snon}
319267468Snon
319379697Snonstatic int
319479697Snonscsi_low_wide(slp)
319579697Snon	struct scsi_low_softc *slp;
319679697Snon{
319779697Snon	struct targ_info *ti = slp->sl_Tnexus;
319879697Snon	int error;
319979697Snon
320079697Snon	ti->ti_width = MSGIN_WIDTHP(ti);
320179697Snon	error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_WIDE);
320279697Snon	if (error != 0)
320379697Snon	{
320479697Snon		/* XXX:
320579697Snon		 * Current width is not acceptable for our adapter.
320679697Snon		 * The adapter changes max width.
320779697Snon		 */
3208240325Sjhb		device_printf(slp->sl_dev,
3209240325Sjhb		    "wide neg failed. retry wide msg neg ...\n");
321079697Snon		return error;
321179697Snon	}
321279697Snon
321379697Snon	ti->ti_owidth = ti->ti_width;
321479697Snon	if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
321579697Snon	{
321679697Snon		ti->ti_setup_msg_done |=
321779697Snon			(SCSI_LOW_MSG_SYNCH | SCSI_LOW_MSG_WIDE);
321879697Snon	}
321979697Snon
322079697Snon	/* inform data */
322179697Snon	if ((slp->sl_show_result & SHOW_WIDE_NEG) != 0)
322279697Snon	{
322379697Snon#ifdef	SCSI_LOW_NEGOTIATE_BEFORE_SENSE
322479697Snon		struct slccb *cb = slp->sl_Qnexus;
322579697Snon
322679697Snon		if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
322779697Snon			return 0;
322879697Snon#endif	/* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
322979697Snon
3230240325Sjhb		device_printf(slp->sl_dev, "(%d:*): transfer width %d bits\n",
3231240325Sjhb		    ti->ti_id, 1 << (3 + ti->ti_width));
323279697Snon	}
323367468Snon	return 0;
323467468Snon}
323567468Snon
323667468Snonstatic int
323779697Snonscsi_low_msginfunc_simple_qtag(slp)
323879697Snon	struct scsi_low_softc *slp;
323967468Snon{
324079697Snon	struct targ_info *ti = slp->sl_Tnexus;
324179697Snon	scsi_low_tag_t etag = (scsi_low_tag_t) ti->ti_msgin[1];
324279697Snon
324379697Snon	if (slp->sl_Qnexus != NULL)
324479697Snon	{
324579697Snon		if (slp->sl_Qnexus->ccb_tag != etag)
324679697Snon		{
324779697Snon			slp->sl_error |= FATALIO;
324879697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
324979697Snon			SCSI_LOW_INFO(slp, ti, "MSGIN: qtag mismatch");
325079697Snon		}
325179697Snon	}
325279697Snon	else if (scsi_low_establish_ccb(ti, slp->sl_Lnexus, etag) == NULL)
325379697Snon	{
325479697Snon#ifdef	SCSI_LOW_DEBUG
325579697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id))
325679697Snon			return 0;
325779697Snon#endif	/* SCSI_LOW_DEBUG */
325879697Snon
325979697Snon		slp->sl_error |= FATALIO;
326079697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT_QTAG, 0);
326179697Snon		SCSI_LOW_INFO(slp, ti, "MSGIN: taged ccb not found");
326279697Snon	}
326379697Snon	return 0;
326479697Snon}
326579697Snon
326679697Snonstatic int
326779697Snonscsi_low_msginfunc_i_wide_residue(slp)
326879697Snon	struct scsi_low_softc *slp;
326979697Snon{
327079697Snon	struct targ_info *ti = slp->sl_Tnexus;
327179697Snon	struct slccb *cb = slp->sl_Qnexus;
327279697Snon	int res = (int) ti->ti_msgin[1];
327379697Snon
327479697Snon	if (cb == NULL || res <= 0 ||
327579697Snon	    (ti->ti_width == SCSI_LOW_BUS_WIDTH_16 && res > 1) ||
327679697Snon	    (ti->ti_width == SCSI_LOW_BUS_WIDTH_32 && res > 3))
327779697Snon		return EINVAL;
327879697Snon
327979697Snon	if (slp->sl_scp.scp_datalen + res > cb->ccb_scp.scp_datalen)
328079697Snon		return EINVAL;
328179697Snon
328279697Snon	slp->sl_scp.scp_datalen += res;
328379697Snon	slp->sl_scp.scp_data -= res;
328479697Snon	scsi_low_data_finish(slp);
328579697Snon	return 0;
328679697Snon}
328779697Snon
328879697Snonstatic int
328979697Snonscsi_low_msginfunc_ext(slp)
329079697Snon	struct scsi_low_softc *slp;
329179697Snon{
329279697Snon	struct slccb *cb = slp->sl_Qnexus;
329379697Snon	struct lun_info *li = slp->sl_Lnexus;
329479697Snon	struct targ_info *ti = slp->sl_Tnexus;
329567468Snon	int count, retry;
329667468Snon	u_int32_t *ptr;
329767468Snon
329867468Snon	if (ti->ti_msginptr == 2)
329967468Snon	{
330067468Snon		ti->ti_msginlen = ti->ti_msgin[1] + 2;
330167468Snon		return 0;
330267468Snon	}
330367468Snon
330467468Snon	switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2]))
330567468Snon	{
330667468Snon	case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE):
330767468Snon		if (cb == NULL)
330867468Snon			break;
330967468Snon
331067468Snon		ptr = (u_int32_t *)(&ti->ti_msgin[3]);
331167468Snon		count = (int) htonl((long) (*ptr));
331267468Snon		if(slp->sl_scp.scp_datalen - count < 0 ||
331367468Snon		   slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen)
331467468Snon			break;
331567468Snon
331667468Snon		slp->sl_scp.scp_datalen -= count;
331767468Snon		slp->sl_scp.scp_data += count;
331867468Snon		return 0;
331967468Snon
332067468Snon	case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE):
332167468Snon		if (li == NULL)
332267468Snon			break;
332367468Snon
332479697Snon		retry = scsi_low_synch(slp);
332567468Snon		if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0)
332667468Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0);
332779697Snon
332879697Snon#ifdef	SCSI_LOW_DEBUG
332979697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
333079697Snon		{
333179697Snon			scsi_low_test_atten(slp, ti, SCSI_LOW_MSG_SYNCH);
333279697Snon		}
333379697Snon#endif	/* SCSI_LOW_DEBUG */
333467468Snon		return 0;
333567468Snon
333667468Snon	case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE):
333767468Snon		if (li == NULL)
333867468Snon			break;
333967468Snon
334079697Snon		retry = scsi_low_wide(slp);
334179697Snon		if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_WIDE) == 0)
334279697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0);
334379697Snon
334467468Snon		return 0;
334567468Snon
334667468Snon	default:
334767468Snon		break;
334867468Snon	}
334967468Snon
335067468Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
335167468Snon	return EINVAL;
335267468Snon}
335367468Snon
335467468Snonstatic int
335579697Snonscsi_low_msginfunc_parity(slp)
335679697Snon	struct scsi_low_softc *slp;
335767468Snon{
335879697Snon	struct targ_info *ti = slp->sl_Tnexus;
335967468Snon
336079697Snon	/* only I -> T, invalid! */
336179697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
336267468Snon	return 0;
336367468Snon}
336467468Snon
336567468Snonstatic int
336679697Snonscsi_low_msginfunc_msg_reject(slp)
336779697Snon	struct scsi_low_softc *slp;
336867468Snon{
336979697Snon	struct targ_info *ti = slp->sl_Tnexus;
337067468Snon	struct scsi_low_msgout_data *mdp;
337167468Snon	u_int msgflags;
337267468Snon
337379697Snon	if (ti->ti_emsgflags != 0)
337467468Snon	{
3375240325Sjhb		device_printf(slp->sl_dev, "msg flags [0x%x] rejected\n",
3376240325Sjhb		    ti->ti_emsgflags);
337767468Snon		msgflags = SCSI_LOW_MSG_REJECT;
337867468Snon		mdp = &scsi_low_msgout_data[0];
337967468Snon		for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
338067468Snon		{
338167468Snon			if ((ti->ti_emsgflags & mdp->md_flags) != 0)
338267468Snon			{
338367468Snon				ti->ti_emsgflags &= ~mdp->md_flags;
338467468Snon				if (mdp->md_errfunc != NULL)
338579697Snon					(*mdp->md_errfunc) (slp, msgflags);
338667468Snon				break;
338767468Snon			}
338867468Snon		}
338979697Snon		return 0;
339067468Snon	}
339179697Snon	else
339279697Snon	{
339379697Snon		SCSI_LOW_INFO(slp, ti, "MSGIN: rejected msg not found");
339479697Snon		slp->sl_error |= MSGERR;
339579697Snon	}
339679697Snon	return EINVAL;
339767468Snon}
339867468Snon
339979697Snonint
340067468Snonscsi_low_msgin(slp, ti, c)
340167468Snon	struct scsi_low_softc *slp;
340267468Snon	struct targ_info *ti;
340379697Snon	u_int c;
340467468Snon{
340567468Snon	struct scsi_low_msgin_data *sdp;
340667468Snon	struct lun_info *li;
340767468Snon	u_int8_t msg;
340867468Snon
340979697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
341079697Snon	if (ti != slp->sl_Tnexus)
341179697Snon	{
341279697Snon		scsi_low_print(slp, NULL);
341379697Snon		panic("scsi_low_msgin: Target nexus inconsistent");
341479697Snon	}
341579697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
341679697Snon
341767468Snon	/*
341867468Snon	 * Phase changes, clear the pointer.
341967468Snon	 */
342067468Snon	if (ti->ti_ophase != ti->ti_phase)
342167468Snon	{
342267468Snon		MSGINPTR_CLR(ti);
342379697Snon		ti->ti_msgin_parity_error = 0;
342479697Snon
342579697Snon		slp->sl_ph_count ++;
342679697Snon		if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
342779697Snon		{
3428240325Sjhb			device_printf(slp->sl_dev, "too many phase changes\n");
342979697Snon			slp->sl_error |= FATALIO;
343079697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
343179697Snon		}
343267468Snon	}
343367468Snon
343467468Snon	/*
343567468Snon	 * Store a current messages byte into buffer and
343667468Snon	 * wait for the completion of the current msg.
343767468Snon	 */
343879697Snon	ti->ti_msgin[ti->ti_msginptr ++] = (u_int8_t) c;
343967468Snon	if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN)
344067468Snon	{
344167468Snon		ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1;
344267468Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
344367468Snon	}
344467468Snon
344567468Snon	/*
344679697Snon	 * Check parity errors.
344779697Snon	 */
344879697Snon	if ((c & SCSI_LOW_DATA_PE) != 0)
344979697Snon	{
345079697Snon		ti->ti_msgin_parity_error ++;
345179697Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
345279697Snon		goto out;
345379697Snon	}
345479697Snon
345579697Snon	if (ti->ti_msgin_parity_error != 0)
345679697Snon		goto out;
345779697Snon
345879697Snon	/*
345967468Snon	 * Calculate messages length.
346067468Snon	 */
346167468Snon	msg = ti->ti_msgin[0];
346267468Snon	if (msg < MSGIN_DATA_LAST)
346367468Snon		sdp = &scsi_low_msgin_data[msg];
346467468Snon	else
346567468Snon		sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST];
346667468Snon
346767468Snon	if (ti->ti_msginlen == 0)
346867468Snon	{
346967468Snon		ti->ti_msginlen = sdp->md_len;
347067468Snon	}
347167468Snon
347267468Snon	/*
347367468Snon	 * Check comletion.
347467468Snon	 */
347567468Snon	if (ti->ti_msginptr < ti->ti_msginlen)
347679697Snon		return EJUSTRETURN;
347767468Snon
347867468Snon	/*
347967468Snon	 * Do process.
348067468Snon	 */
348167468Snon	if ((msg & MSG_IDENTIFY) == 0)
348267468Snon	{
348379697Snon		if (((*sdp->md_msgfunc) (slp)) == EJUSTRETURN)
348479697Snon			return EJUSTRETURN;
348567468Snon	}
348667468Snon	else
348767468Snon	{
348879697Snon		li = slp->sl_Lnexus;
348967468Snon		if (li == NULL)
349067468Snon		{
349179697Snon			li = scsi_low_alloc_li(ti, MSGCMD_LUN(msg), 0);
349267468Snon			if (li == NULL)
349367468Snon				goto badlun;
349479697Snon			slp->sl_Lnexus = li;
349579697Snon			(*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
349667468Snon		}
349779697Snon		else
349879697Snon		{
349979697Snon			if (MSGCMD_LUN(msg) != li->li_lun)
350079697Snon				goto badlun;
350179697Snon		}
350267468Snon
350379697Snon		if (slp->sl_Qnexus == NULL && li->li_nqio == 0)
350467468Snon		{
350567468Snon			if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG))
350679697Snon			{
350779697Snon#ifdef	SCSI_LOW_DEBUG
350879697Snon				if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
350979697Snon				{
351079697Snon					goto out;
351179697Snon				}
351279697Snon#endif	/* SCSI_LOW_DEBUG */
351367468Snon				goto badlun;
351479697Snon			}
351567468Snon		}
351667468Snon	}
351779697Snon	goto out;
351867468Snon
351967468Snon	/*
352079697Snon	 * Msg process completed, reset msgin pointer and assert ATN if desired.
352167468Snon	 */
352279697Snonbadlun:
352379697Snon	slp->sl_error |= FATALIO;
352479697Snon	scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
352579697Snon	SCSI_LOW_INFO(slp, ti, "MSGIN: identify wrong");
352679697Snon
352779697Snonout:
352879697Snon	if (ti->ti_msginptr < ti->ti_msginlen)
352979697Snon		return EJUSTRETURN;
353079697Snon
353179697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
353279697Snon	scsi_low_msg_log_write(&ti->ti_log_msgin,
353379697Snon			       &ti->ti_msgin[0], ti->ti_msginlen);
353479697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
353579697Snon
353679697Snon	MSGINPTR_CLR(ti);
353779697Snon	return 0;
353879697Snon}
353979697Snon
354079697Snon/**********************************************************
354179697Snon * disconnect
354279697Snon **********************************************************/
354379697Snonint
354479697Snonscsi_low_disconnected(slp, ti)
354579697Snon	struct scsi_low_softc *slp;
354679697Snon	struct targ_info *ti;
354779697Snon{
354879697Snon	struct slccb *cb = slp->sl_Qnexus;
354979697Snon
355079697Snon	/* check phase completion */
355179697Snon	switch (slp->sl_msgphase)
355267468Snon	{
355379697Snon	case MSGPH_RESET:
355479697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
355579697Snon		scsi_low_msginfunc_cc(slp);
355679697Snon		scsi_low_reset_nexus_target(slp, slp->sl_Tnexus, 0);
355779697Snon		goto io_resume;
355867468Snon
355979697Snon	case MSGPH_ABORT:
356079697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
356179697Snon		scsi_low_msginfunc_cc(slp);
356279697Snon		scsi_low_reset_nexus_lun(slp, slp->sl_Lnexus, 0);
356379697Snon		goto io_resume;
356479697Snon
356579697Snon	case MSGPH_TERM:
356679697Snon		scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
356779697Snon		scsi_low_msginfunc_cc(slp);
356879697Snon		goto io_resume;
356979697Snon
357079697Snon	case MSGPH_DISC:
357179697Snon		if (cb != NULL)
357267468Snon		{
357379697Snon			struct lun_info *li;
357479697Snon
357579697Snon			li = cb->li;
357679697Snon			TAILQ_INSERT_TAIL(&li->li_discq, cb, ccb_chain);
357779697Snon			cb->ccb_flags |= CCB_DISCQ;
357879697Snon			cb->ccb_error |= slp->sl_error;
357979697Snon			li->li_disc ++;
358079697Snon			ti->ti_disc ++;
358179697Snon			slp->sl_disc ++;
358279697Snon		}
358379697Snon
358479697Snon#ifdef	SCSI_LOW_STATICS
358579697Snon		scsi_low_statics.nexus_disconnected ++;
358679697Snon#endif	/* SCSI_LOW_STATICS */
358779697Snon
358879697Snon#ifdef	SCSI_LOW_DEBUG
358979697Snon		if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DISC, ti->ti_id) != 0)
359079697Snon		{
359179697Snon			printf("## SCSI_LOW_DISCONNECTED ===============\n");
359279697Snon			scsi_low_print(slp, NULL);
359379697Snon		}
359479697Snon#endif	/* SCSI_LOW_DEBUG */
359579697Snon		break;
359679697Snon
359779697Snon	case MSGPH_NULL:
359879697Snon		slp->sl_error |= FATALIO;
359979697Snon		if (ti->ti_phase == PH_SELSTART)
360079697Snon			slp->sl_error |= SELTIMEOUTIO;
360179697Snon		else
360279697Snon			slp->sl_error |= UBFERR;
360379697Snon		/* fall through */
360479697Snon
360579697Snon	case MSGPH_LCTERM:
360679697Snon	case MSGPH_CMDC:
360779697Snonio_resume:
360879697Snon		if (cb == NULL)
360979697Snon			break;
361079697Snon
361179697Snon#ifdef	SCSI_LOW_DEBUG
361279697Snon		if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
361379697Snon		{
361479697Snon			if (cb->ccb_omsgoutflag == SCSI_LOW_MSG_NOOP &&
361579697Snon			    (cb->ccb_msgoutflag != 0 ||
361679697Snon			     (ti->ti_msgflags & SCSI_LOW_MSG_NOOP)))
361779697Snon			{
361879697Snon				scsi_low_info(slp, ti, "ATTEN CHECK FAILED");
361979697Snon			}
362079697Snon		}
362179697Snon#endif	/* SCSI_LOW_DEBUG */
362279697Snon
362379697Snon		cb->ccb_error |= slp->sl_error;
362479697Snon		if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
362579697Snon		{
362679697Snon			cb->ccb_flags |= CCB_STARTQ;
362779697Snon			TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
362879697Snon		}
362979697Snon		break;
363079697Snon	}
363179697Snon
363279697Snon	scsi_low_bus_release(slp, ti);
363379697Snon	scsi_low_start(slp);
363479697Snon	return 1;
363579697Snon}
363679697Snon
363779697Snon/**********************************************************
363879697Snon * TAG operations
363979697Snon **********************************************************/
3640104094Sphkstatic int
364179697Snonscsi_low_alloc_qtag(cb)
364279697Snon	struct slccb *cb;
364379697Snon{
364479697Snon	struct lun_info *li = cb->li;
364579697Snon	scsi_low_tag_t etag;
364679697Snon
364779697Snon	if (cb->ccb_otag != SCSI_LOW_UNKTAG)
364879697Snon		return 0;
364979697Snon
365079697Snon#ifndef	SCSI_LOW_ALT_QTAG_ALLOCATE
365179697Snon	etag = ffs(li->li_qtagbits);
365279697Snon	if (etag == 0)
365379697Snon		return ENOSPC;
365479697Snon
365579697Snon	li->li_qtagbits &= ~(1 << (etag - 1));
365679697Snon	cb->ccb_otag = etag;
365779697Snon	return 0;
365879697Snon
365979697Snon#else	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
366079697Snon	for (etag = li->li_qd ; li->li_qd < SCSI_LOW_MAXNEXUS; li->li_qd ++)
366179697Snon		if (li->li_qtagarray[li->li_qd] == 0)
366279697Snon			goto found;
366379697Snon
366479697Snon	for (li->li_qd = 0; li->li_qd < etag; li->li_qd ++)
366579697Snon		if (li->li_qtagarray[li->li_qd] == 0)
366679697Snon			goto found;
366779697Snon
366879697Snon	return ENOSPC;
366979697Snon
367079697Snonfound:
367179697Snon	li->li_qtagarray[li->li_qd] ++;
367279697Snon	cb->ccb_otag = (li->li_qd ++);
367379697Snon	return 0;
367479697Snon#endif	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
367579697Snon}
367679697Snon
3677104094Sphkstatic int
367879697Snonscsi_low_dealloc_qtag(cb)
367979697Snon	struct slccb *cb;
368079697Snon{
368179697Snon	struct lun_info *li = cb->li;
368279697Snon	scsi_low_tag_t etag;
368379697Snon
368479697Snon	if (cb->ccb_otag == SCSI_LOW_UNKTAG)
368579697Snon		return 0;
368679697Snon
368779697Snon#ifndef	SCSI_LOW_ALT_QTAG_ALLOCATE
368879697Snon	etag = cb->ccb_otag - 1;
368967468Snon#ifdef	SCSI_LOW_DIAGNOSTIC
369079697Snon	if (etag >= sizeof(li->li_qtagbits) * NBBY)
369179697Snon		panic("scsi_low_dealloc_tag: illegal tag");
369267468Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
369379697Snon	li->li_qtagbits |= (1 << etag);
369479697Snon
369579697Snon#else	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
369679697Snon	etag = cb->ccb_otag;
369779697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
369879697Snon	if (etag >= SCSI_LOW_MAXNEXUS)
369979697Snon		panic("scsi_low_dealloc_tag: illegal tag");
370079697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
370179697Snon	li->li_qtagarray[etag] --;
370279697Snon#endif	/* SCSI_LOW_ALT_QTAG_ALLOCATE */
370379697Snon
370479697Snon	cb->ccb_otag = SCSI_LOW_UNKTAG;
370579697Snon	return 0;
370679697Snon}
370779697Snon
3708104094Sphkstatic struct slccb *
370979697Snonscsi_low_revoke_ccb(slp, cb, fdone)
371079697Snon	struct scsi_low_softc *slp;
371179697Snon	struct slccb *cb;
371279697Snon	int fdone;
371379697Snon{
371479697Snon	struct targ_info *ti = cb->ti;
371579697Snon	struct lun_info *li = cb->li;
371679697Snon
371779697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
371879697Snon	if ((cb->ccb_flags & (CCB_STARTQ | CCB_DISCQ)) ==
371979697Snon	    (CCB_STARTQ | CCB_DISCQ))
372079697Snon	{
3721240325Sjhb		panic("%s: ccb in both queue",
3722240325Sjhb		    device_get_nameunit(slp->sl_dev));
372367468Snon	}
372479697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
372567468Snon
372679697Snon	if ((cb->ccb_flags & CCB_STARTQ) != 0)
372779697Snon	{
372879697Snon		TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
372979697Snon	}
373079697Snon
373179697Snon	if ((cb->ccb_flags & CCB_DISCQ) != 0)
373279697Snon	{
373379697Snon		TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
373479697Snon		li->li_disc --;
373579697Snon		ti->ti_disc --;
373679697Snon		slp->sl_disc --;
373779697Snon	}
373879697Snon
373979697Snon	cb->ccb_flags &= ~(CCB_STARTQ | CCB_DISCQ |
374079697Snon			   CCB_SENSE | CCB_CLEARQ | CCB_INTERNAL);
374179697Snon
374279697Snon	if (fdone != 0 &&
374379697Snon	    (cb->ccb_rcnt ++ >= slp->sl_max_retry ||
374479697Snon	     (cb->ccb_flags & CCB_NORETRY) != 0))
374579697Snon	{
374679697Snon		cb->ccb_error |= FATALIO;
374779697Snon		cb->ccb_flags &= ~CCB_AUTOSENSE;
374879697Snon		if (scsi_low_done(slp, cb) != SCSI_LOW_DONE_COMPLETE)
3749240325Sjhb			panic("%s: done ccb retried",
3750240325Sjhb			    device_get_nameunit(slp->sl_dev));
375179697Snon		return NULL;
375279697Snon	}
375379697Snon	else
375479697Snon	{
375579697Snon		cb->ccb_error |= PENDINGIO;
375679697Snon		scsi_low_deactivate_qtag(cb);
375779697Snon		scsi_low_ccb_message_retry(cb);
375879697Snon		cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
375979697Snon		return cb;
376079697Snon	}
376167468Snon}
376267468Snon
3763104094Sphkstatic void
376479697Snonscsi_low_reset_nexus_lun(slp, li, fdone)
376579697Snon	struct scsi_low_softc *slp;
376679697Snon	struct lun_info *li;
376779697Snon	int fdone;
376879697Snon{
376979697Snon	struct slccb *cb, *ncb, *ecb;
377079697Snon
377179697Snon	if (li == NULL)
377279697Snon		return;
377379697Snon
377479697Snon	ecb = NULL;
377579697Snon	for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = ncb)
377679697Snon	{
377779697Snon		ncb = TAILQ_NEXT(cb, ccb_chain);
377879697Snon		cb = scsi_low_revoke_ccb(slp, cb, fdone);
377979697Snon		if (cb != NULL)
378079697Snon		{
378179697Snon			/*
378279697Snon			 * presumely keep ordering of io
378379697Snon			 */
378479697Snon			cb->ccb_flags |= CCB_STARTQ;
378579697Snon			if (ecb == NULL)
378679697Snon			{
378779697Snon				TAILQ_INSERT_HEAD(&slp->sl_start,\
378879697Snon						  cb, ccb_chain);
378979697Snon			}
379079697Snon			else
379179697Snon			{
379279697Snon				TAILQ_INSERT_AFTER(&slp->sl_start,\
379379697Snon						   ecb, cb, ccb_chain);
379479697Snon			}
379579697Snon			ecb = cb;
379679697Snon		}
379779697Snon	}
379879697Snon}
379979697Snon
380067468Snon/**************************************************************
380167468Snon * Qurik setup
380267468Snon **************************************************************/
380367468Snonstatic void
380479697Snonscsi_low_calcf_lun(li)
380567468Snon	struct lun_info *li;
380667468Snon{
380779697Snon	struct targ_info *ti = li->li_ti;
380867468Snon	struct scsi_low_softc *slp = ti->ti_sc;
380979697Snon	u_int cfgflags, diskflags;
381067468Snon
381179697Snon	if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID)
381279697Snon		cfgflags = li->li_cfgflags;
381379697Snon	else
381479697Snon		cfgflags = 0;
381579697Snon
381679697Snon	diskflags = li->li_diskflags & li->li_quirks;
381779697Snon
381879697Snon	/* disconnect */
381967468Snon	li->li_flags &= ~SCSI_LOW_DISC;
382067468Snon	if ((slp->sl_cfgflags & CFG_NODISC) == 0 &&
382179697Snon	    (diskflags & SCSI_LOW_DISK_DISC) != 0 &&
382279697Snon	    (cfgflags & SCSI_LOW_DISC) != 0)
382367468Snon		li->li_flags |= SCSI_LOW_DISC;
382467468Snon
382579697Snon	/* parity */
382667468Snon	li->li_flags |= SCSI_LOW_NOPARITY;
382767468Snon	if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 &&
382879697Snon	    (diskflags & SCSI_LOW_DISK_PARITY) != 0 &&
382979697Snon	    (cfgflags & SCSI_LOW_NOPARITY) == 0)
383067468Snon		li->li_flags &= ~SCSI_LOW_NOPARITY;
383167468Snon
383279697Snon	/* qtag */
383379697Snon	if ((slp->sl_cfgflags & CFG_NOQTAG) == 0 &&
383479697Snon	    (cfgflags & SCSI_LOW_QTAG) != 0 &&
383579697Snon	    (diskflags & SCSI_LOW_DISK_QTAG) != 0)
383679697Snon	{
383779697Snon		li->li_flags |= SCSI_LOW_QTAG;
383879697Snon		li->li_maxnexus = SCSI_LOW_MAXNEXUS;
383979697Snon		li->li_maxnqio = li->li_maxnexus;
384079697Snon	}
384179697Snon	else
384279697Snon	{
384379697Snon		li->li_flags &= ~SCSI_LOW_QTAG;
384479697Snon		li->li_maxnexus = 0;
384579697Snon		li->li_maxnqio = li->li_maxnexus;
384679697Snon	}
384779697Snon
384879697Snon	/* cmd link */
384979697Snon	li->li_flags &= ~SCSI_LOW_LINK;
385079697Snon	if ((cfgflags & SCSI_LOW_LINK) != 0 &&
385179697Snon	    (diskflags & SCSI_LOW_DISK_LINK) != 0)
385279697Snon		li->li_flags |= SCSI_LOW_LINK;
385379697Snon
385479697Snon	/* compatible flags */
385567468Snon	li->li_flags &= ~SCSI_LOW_SYNC;
385679697Snon	if (ti->ti_maxsynch.offset > 0)
385779697Snon		li->li_flags |= SCSI_LOW_SYNC;
385879697Snon
385979697Snon#ifdef	SCSI_LOW_DEBUG
386079697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
386167468Snon	{
386279697Snon		scsi_low_calcf_show(li);
386367468Snon	}
386479697Snon#endif	/* SCSI_LOW_DEBUG */
386579697Snon}
386679697Snon
386779697Snonstatic void
386879697Snonscsi_low_calcf_target(ti)
386979697Snon	struct targ_info *ti;
387079697Snon{
387179697Snon	struct scsi_low_softc *slp = ti->ti_sc;
387279697Snon	u_int offset, period, diskflags;
387379697Snon
387479697Snon	diskflags = ti->ti_diskflags & ti->ti_quirks;
387579697Snon
387679697Snon	/* synch */
387779697Snon	if ((slp->sl_cfgflags & CFG_ASYNC) == 0 &&
387879697Snon	    (diskflags & SCSI_LOW_DISK_SYNC) != 0)
387979697Snon	{
388079697Snon		offset = ti->ti_maxsynch.offset;
388179697Snon		period = ti->ti_maxsynch.period;
388279697Snon		if (offset == 0 || period == 0)
388379697Snon			offset = period = 0;
388479697Snon	}
388567468Snon	else
388679697Snon	{
388779697Snon		offset = period = 0;
388879697Snon	}
388967468Snon
389079697Snon	ti->ti_maxsynch.offset = offset;
389179697Snon	ti->ti_maxsynch.period = period;
389279697Snon
389379697Snon	/* wide */
389479697Snon	if ((diskflags & SCSI_LOW_DISK_WIDE_32) == 0 &&
389579697Snon	     ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
389679697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_16;
389779697Snon
389879697Snon	if ((diskflags & SCSI_LOW_DISK_WIDE_16) == 0 &&
389979697Snon	    ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
390079697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
390179697Snon
390279697Snon	if (ti->ti_flags_valid == SCSI_LOW_TARG_FLAGS_ALL_VALID)
390367468Snon	{
390479697Snon		if (ti->ti_maxsynch.offset != ti->ti_osynch.offset ||
390579697Snon		    ti->ti_maxsynch.period != ti->ti_osynch.period)
390679697Snon			ti->ti_setup_msg |= SCSI_LOW_MSG_SYNCH;
390779697Snon		if (ti->ti_width != ti->ti_owidth)
390879697Snon			ti->ti_setup_msg |= (SCSI_LOW_MSG_WIDE | SCSI_LOW_MSG_SYNCH);
390979697Snon
391079697Snon		ti->ti_osynch = ti->ti_maxsynch;
391179697Snon		ti->ti_owidth = ti->ti_width;
391267468Snon	}
391367468Snon
391479697Snon#ifdef	SCSI_LOW_DEBUG
391579697Snon	if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
391679697Snon	{
3917240325Sjhb		device_printf(slp->sl_dev,
3918240325Sjhb			"(%d:*): max period(%dns) offset(%d) width(%d)\n",
3919240325Sjhb			ti->ti_id,
392079697Snon			ti->ti_maxsynch.period * 4,
392179697Snon			ti->ti_maxsynch.offset,
392279697Snon			ti->ti_width);
392379697Snon	}
392479697Snon#endif	/* SCSI_LOW_DEBUG */
392567468Snon}
392667468Snon
392779697Snonstatic void
392879697Snonscsi_low_calcf_show(li)
392979697Snon	struct lun_info *li;
393079697Snon{
393179697Snon	struct targ_info *ti = li->li_ti;
393279697Snon	struct scsi_low_softc *slp = ti->ti_sc;
393379697Snon
3934240325Sjhb	device_printf(slp->sl_dev,
3935240325Sjhb		"(%d:%d): period(%d ns) offset(%d) width(%d) flags 0x%b\n",
3936240325Sjhb		ti->ti_id, li->li_lun,
393779697Snon		ti->ti_maxsynch.period * 4,
393879697Snon		ti->ti_maxsynch.offset,
393979697Snon		ti->ti_width,
394079697Snon		li->li_flags, SCSI_LOW_BITS);
394179697Snon}
394279697Snon
394379697Snon#ifdef	SCSI_LOW_START_UP_CHECK
394479697Snon/**************************************************************
394579697Snon * scsi world start up
394679697Snon **************************************************************/
394792770Salfredstatic int scsi_low_poll(struct scsi_low_softc *, struct slccb *);
394879697Snon
394967468Snonstatic int
395079697Snonscsi_low_start_up(slp)
395179697Snon	struct scsi_low_softc *slp;
395267468Snon{
395367468Snon	struct targ_info *ti;
395467468Snon	struct lun_info *li;
395579697Snon	struct slccb *cb;
395679697Snon	int target, lun;
395767468Snon
3958240325Sjhb	device_printf(slp->sl_dev, "scsi_low: probing all devices ....\n");
395967468Snon
396079697Snon	for (target = 0; target < slp->sl_ntargs; target ++)
396179697Snon	{
396279697Snon		if (target == slp->sl_hostid)
396379697Snon		{
396479697Snon			if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
396579697Snon			{
3966240325Sjhb				device_printf(slp->sl_dev,
3967240325Sjhb				    "scsi_low: target %d (host card)\n",
3968240325Sjhb				    target);
396979697Snon			}
397079697Snon			continue;
397179697Snon		}
397267468Snon
397379697Snon		if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
397479697Snon		{
3975240325Sjhb			device_printf(slp->sl_dev, "scsi_low: target %d lun ",
3976240325Sjhb			    target);
397779697Snon		}
397867468Snon
397979697Snon		ti = slp->sl_ti[target];
398079697Snon		for (lun = 0; lun < slp->sl_nluns; lun ++)
398179697Snon		{
398279697Snon			if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
398379697Snon				break;
398479697Snon
398579697Snon			cb->osdep = NULL;
398679697Snon			cb->bp = NULL;
398779697Snon
398879697Snon			li = scsi_low_alloc_li(ti, lun, 1);
398979697Snon
399079697Snon			scsi_low_enqueue(slp, ti, li, cb,
399179697Snon					 CCB_AUTOSENSE | CCB_POLLED, 0);
399279697Snon
399379697Snon			scsi_low_poll(slp, cb);
399479697Snon
399579697Snon			if (li->li_state != SCSI_LOW_LUN_OK)
399679697Snon				break;
399779697Snon
399879697Snon			if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
399979697Snon			{
400079697Snon				printf("%d ", lun);
400179697Snon			}
400279697Snon		}
400379697Snon
400479697Snon		if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
400579697Snon		{
400679697Snon			printf("\n");
400779697Snon		}
400879697Snon	}
400967468Snon	return 0;
401067468Snon}
401167468Snon
401279697Snonstatic int
401379697Snonscsi_low_poll(slp, cb)
401479697Snon	struct scsi_low_softc *slp;
401579697Snon	struct slccb *cb;
401679697Snon{
401779697Snon	int tcount;
401879697Snon
401979697Snon	tcount = 0;
402079697Snon	while (slp->sl_nio > 0)
402179697Snon	{
4022240172Sjhb		DELAY((1000 * 1000) / SCSI_LOW_POLL_HZ);
402379697Snon
402479697Snon		(*slp->sl_funcs->scsi_low_poll) (slp);
402579697Snon		if (tcount ++ < SCSI_LOW_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
402679697Snon			continue;
402779697Snon
402879697Snon		tcount = 0;
402979697Snon		scsi_low_timeout_check(slp);
403079697Snon	}
403179697Snon
403279697Snon	return 0;
403379697Snon}
403479697Snon#endif	/* SCSI_LOW_START_UP_CHECK */
403579697Snon
403667468Snon/**********************************************************
403767468Snon * DEBUG SECTION
403867468Snon **********************************************************/
403979697Snon#ifdef	SCSI_LOW_DEBUG
404067468Snonstatic void
404179697Snonscsi_low_test_abort(slp, ti, li)
404279697Snon	struct scsi_low_softc *slp;
404379697Snon	struct targ_info *ti;
404479697Snon	struct lun_info *li;
404579697Snon{
404679697Snon	struct slccb *acb;
404779697Snon
404879697Snon	if (li->li_disc > 1)
404979697Snon	{
405079697Snon		acb = TAILQ_FIRST(&li->li_discq);
405179697Snon		if (scsi_low_abort_ccb(slp, acb) == 0)
405279697Snon		{
4053240325Sjhb			device_printf(slp->sl_dev,
4054240325Sjhb			    "aborting ccb(0x%lx) start\n", (u_long) acb);
405579697Snon		}
405679697Snon	}
405779697Snon}
405879697Snon
405979697Snonstatic void
406079697Snonscsi_low_test_atten(slp, ti, msg)
406179697Snon	struct scsi_low_softc *slp;
406279697Snon	struct targ_info *ti;
406379697Snon	u_int msg;
406479697Snon{
406579697Snon
406679697Snon	if (slp->sl_ph_count < SCSI_LOW_MAX_ATTEN_CHECK)
406779697Snon		scsi_low_assert_msg(slp, ti, msg, 0);
406879697Snon	else
4069240325Sjhb		device_printf(slp->sl_dev, "atten check OK\n");
407079697Snon}
407179697Snon
407279697Snonstatic void
407379697Snonscsi_low_test_cmdlnk(slp, cb)
407479697Snon	struct scsi_low_softc *slp;
407579697Snon	struct slccb *cb;
407679697Snon{
407779697Snon#define	SCSI_LOW_CMDLNK_NOK	(CCB_INTERNAL | CCB_SENSE | CCB_CLEARQ)
407879697Snon
407979697Snon	if ((cb->ccb_flags & SCSI_LOW_CMDLNK_NOK) != 0)
408079697Snon		return;
408179697Snon
408279697Snon	memcpy(cb->ccb_scsi_cmd, slp->sl_scp.scp_cmd,
408379697Snon	       slp->sl_scp.scp_cmdlen);
408479697Snon	cb->ccb_scsi_cmd[slp->sl_scp.scp_cmdlen - 1] |= 1;
408579697Snon	slp->sl_scp.scp_cmd = cb->ccb_scsi_cmd;
408679697Snon}
408779697Snon#endif	/* SCSI_LOW_DEBUG */
408879697Snon
408979697Snon/* static */ void
409067468Snonscsi_low_info(slp, ti, s)
409167468Snon	struct scsi_low_softc *slp;
409267468Snon	struct targ_info *ti;
409367468Snon	u_char *s;
409467468Snon{
409567468Snon
409679697Snon	if (slp == NULL)
409779697Snon		slp = LIST_FIRST(&sl_tab);
409879697Snon	if (s == NULL)
409979697Snon		s = "no message";
410079697Snon
410179697Snon	printf(">>>>> SCSI_LOW_INFO(0x%lx): %s\n", (u_long) slp->sl_Tnexus, s);
410267468Snon	if (ti == NULL)
410367468Snon	{
4104270225Sjhb		TAILQ_FOREACH(ti, &slp->sl_titab, ti_chain)
410579697Snon		{
410667468Snon			scsi_low_print(slp, ti);
410779697Snon		}
410867468Snon	}
410967468Snon	else
411079697Snon	{
411167468Snon		scsi_low_print(slp, ti);
411279697Snon	}
411367468Snon}
411467468Snon
411567468Snonstatic u_char *phase[] =
411667468Snon{
411767468Snon	"FREE", "ARBSTART", "SELSTART", "SELECTED",
411867468Snon	"CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL"
411967468Snon};
412067468Snon
412167468Snonvoid
412267468Snonscsi_low_print(slp, ti)
412367468Snon	struct scsi_low_softc *slp;
412467468Snon	struct targ_info *ti;
412567468Snon{
412679697Snon	struct lun_info *li;
412779697Snon	struct slccb *cb;
412879697Snon	struct sc_p *sp;
412967468Snon
413079697Snon	if (ti == NULL || ti == slp->sl_Tnexus)
413179697Snon	{
413279697Snon		ti = slp->sl_Tnexus;
413379697Snon		li = slp->sl_Lnexus;
413479697Snon		cb = slp->sl_Qnexus;
413579697Snon	}
413679697Snon	else
413779697Snon	{
413879697Snon		li = LIST_FIRST(&ti->ti_litab);
413979697Snon		cb = TAILQ_FIRST(&li->li_discq);
414079697Snon	}
414179697Snon 	sp = &slp->sl_scp;
414267468Snon
4143240325Sjhb	device_printf(slp->sl_dev,
4144240325Sjhb	    "=== NEXUS T(0x%lx) L(0x%lx) Q(0x%lx) NIO(%d) ===\n",
4145240325Sjhb	    (u_long) ti, (u_long) li, (u_long) cb, slp->sl_nio);
414667468Snon
414767468Snon	/* target stat */
414867468Snon	if (ti != NULL)
414967468Snon	{
415079697Snon		u_int flags = 0, maxnqio = 0, nqio = 0;
4151260509Smav		int lun = CAM_LUN_WILDCARD;
415267468Snon
415367468Snon		if (li != NULL)
415467468Snon		{
415567468Snon			lun = li->li_lun;
415667468Snon			flags = li->li_flags;
415779697Snon			maxnqio = li->li_maxnqio;
415879697Snon			nqio = li->li_nqio;
415967468Snon		}
416067468Snon
4161240325Sjhb		device_printf(slp->sl_dev,
4162240325Sjhb		       "(%d:%d) ph<%s> => ph<%s> DISC(%d) QIO(%d:%d)\n",
416367468Snon		       ti->ti_id, lun, phase[(int) ti->ti_ophase],
416479697Snon		       phase[(int) ti->ti_phase], ti->ti_disc,
416579697Snon		       nqio, maxnqio);
416667468Snon
416779697Snon		if (cb != NULL)
416879697Snon		{
416979697Snonprintf("CCB: cmd[0] 0x%x clen 0x%x dlen 0x%x<0x%x stat 0x%x err %b\n",
417079697Snon		       (u_int) cb->ccb_scp.scp_cmd[0],
417179697Snon		       cb->ccb_scp.scp_cmdlen,
417279697Snon		       cb->ccb_datalen,
417379697Snon		       cb->ccb_scp.scp_datalen,
417479697Snon		       (u_int) cb->ccb_sscp.scp_status,
417579697Snon		       cb->ccb_error, SCSI_LOW_ERRORBITS);
417679697Snon		}
417767468Snon
417879697Snonprintf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] attention: %d\n",
417979697Snon	       (u_int) (ti->ti_msginptr),
418079697Snon	       (u_int) (ti->ti_msgin[0]),
418179697Snon	       (u_int) (ti->ti_msgin[1]),
418279697Snon	       (u_int) (ti->ti_msgin[2]),
418379697Snon	       (u_int) (ti->ti_msgin[3]),
418479697Snon	       (u_int) (ti->ti_msgin[4]),
418579697Snon	       slp->sl_atten);
418679697Snon
418767468Snonprintf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n",
418879697Snon		(u_int) ti->ti_msgflags,
418979697Snon		(u_int) (ti->ti_msgoutstr[0]),
419079697Snon		(u_int) (ti->ti_msgoutstr[1]),
419179697Snon		(u_int) (ti->ti_msgoutstr[2]),
419279697Snon		(u_int) (ti->ti_msgoutstr[3]),
419379697Snon		(u_int) (ti->ti_msgoutstr[4]),
419479697Snon		ti->ti_msgoutlen,
419579697Snon		flags, SCSI_LOW_BITS);
419667468Snon
419779697Snon#ifdef	SCSI_LOW_DIAGNOSTIC
419879697Snon		scsi_low_msg_log_show(&ti->ti_log_msgin, "MIN LOG ", 2);
419979697Snon		scsi_low_msg_log_show(&ti->ti_log_msgout, "MOUT LOG", 2);
420079697Snon#endif	/* SCSI_LOW_DIAGNOSTIC */
420167468Snon
420267468Snon	}
420379697Snon
420479697Snon	printf("SCB: daddr 0x%lx dlen 0x%x stat 0x%x err %b\n",
420579697Snon	       (u_long) sp->scp_data,
420679697Snon	       sp->scp_datalen,
420779697Snon	       (u_int) sp->scp_status,
420879697Snon	       slp->sl_error, SCSI_LOW_ERRORBITS);
420967468Snon}
4210