scsi_low.c revision 163816
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: head/sys/cam/scsi/scsi_low.c 163816 2006-10-31 05:53:29Z mjacob $"); 6116162Sobrien 767468Snon#define SCSI_LOW_STATICS 879697Snon#define SCSI_LOW_DEBUG 979697Snon#define SCSI_LOW_NEGOTIATE_BEFORE_SENSE 1079697Snon#define SCSI_LOW_START_UP_CHECK 1179697Snon 1279697Snon/* #define SCSI_LOW_INFO_DETAIL */ 13116162Sobrien 1479697Snon/* #define SCSI_LOW_QCLEAR_AFTER_CA */ 1579697Snon/* #define SCSI_LOW_FLAGS_QUIRKS_OK */ 1679697Snon 1767468Snon#ifdef __NetBSD__ 1867468Snon#define SCSI_LOW_TARGET_OPEN 1979697Snon#endif /* __NetBSD__ */ 2067468Snon 2179697Snon#ifdef __FreeBSD__ 2279697Snon#define SCSI_LOW_FLAGS_QUIRKS_OK 2379697Snon#endif /* __FreeBSD__ */ 2479697Snon 25139743Simp/*- 2667468Snon * [NetBSD for NEC PC-98 series] 2779697Snon * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 2867468Snon * NetBSD/pc98 porting staff. All rights reserved. 2979697Snon * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 3067468Snon * Naofumi HONDA. All rights reserved. 3179697Snon * 3279697Snon * [Ported for FreeBSD CAM] 3379697Snon * Copyright (c) 2000, 2001 3479697Snon * MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro. 3579697Snon * All rights reserved. 3667468Snon * 3767468Snon * Redistribution and use in source and binary forms, with or without 3867468Snon * modification, are permitted provided that the following conditions 3967468Snon * are met: 4067468Snon * 1. Redistributions of source code must retain the above copyright 4167468Snon * notice, this list of conditions and the following disclaimer. 4267468Snon * 2. Redistributions in binary form must reproduce the above copyright 4367468Snon * notice, this list of conditions and the following disclaimer in the 4467468Snon * documentation and/or other materials provided with the distribution. 4567468Snon * 3. The name of the author may not be used to endorse or promote products 4667468Snon * derived from this software without specific prior written permission. 4767468Snon * 4867468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4967468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 5067468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 5167468Snon * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 5267468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 5367468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 5467468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5567468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 5667468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 5767468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 5867468Snon * POSSIBILITY OF SUCH DAMAGE. 5967468Snon */ 6067468Snon 6167468Snon/* <On the nexus establishment> 6267468Snon * When our host is reselected, 6367468Snon * nexus establish processes are little complicated. 6467468Snon * Normal steps are followings: 6579697Snon * 1) Our host selected by target => target nexus (slp->sl_Tnexus) 6679697Snon * 2) Identify msgin => lun nexus (slp->sl_Lnexus) 6779697Snon * 3) Qtag msg => ccb nexus (slp->sl_Qnexus) 6867468Snon */ 6967468Snon#include "opt_ddb.h" 7067468Snon 7167468Snon#include <sys/param.h> 7267468Snon#include <sys/systm.h> 7367468Snon#include <sys/kernel.h> 7479697Snon 7573025Snon#ifdef __FreeBSD__ 7673025Snon#if __FreeBSD_version >= 500001 7767468Snon#include <sys/bio.h> 7879697Snon#else 7979697Snon#include <machine/clock.h> 8073025Snon#endif 8179697Snon#endif /* __FreeBSD__ */ 8279697Snon 8367468Snon#include <sys/buf.h> 8467468Snon#include <sys/queue.h> 8567468Snon#include <sys/malloc.h> 8667468Snon#include <sys/errno.h> 8767468Snon 8879697Snon#ifdef __NetBSD__ 8979697Snon#include <sys/device.h> 9067468Snon#include <vm/vm.h> 9167468Snon 9267468Snon#include <machine/bus.h> 9367468Snon#include <machine/intr.h> 9467468Snon#include <machine/dvcfg.h> 9567468Snon 9667468Snon#include <dev/cons.h> 9767468Snon 9867468Snon#include <dev/scsipi/scsipi_all.h> 9967468Snon#include <dev/scsipi/scsipiconf.h> 10067468Snon#include <dev/scsipi/scsipi_disk.h> 10167468Snon#include <dev/scsipi/scsi_all.h> 10267468Snon#include <dev/scsipi/scsiconf.h> 10379697Snon#include <sys/scsiio.h> 10467468Snon 10567468Snon#include <i386/Cbus/dev/scsi_low.h> 10679697Snon#endif /* __NetBSD__ */ 10779697Snon 10867468Snon#ifdef __FreeBSD__ 10967468Snon#include <cam/cam.h> 11067468Snon#include <cam/cam_ccb.h> 11167468Snon#include <cam/cam_sim.h> 11267468Snon#include <cam/cam_debug.h> 11367468Snon#include <cam/cam_periph.h> 114147723Savatar#include <cam/cam_xpt_periph.h> 11567468Snon 11667468Snon#include <cam/scsi/scsi_all.h> 11773025Snon#include <cam/scsi/scsi_message.h> 11867468Snon 11967468Snon#include <cam/scsi/scsi_low.h> 12067468Snon 12167468Snon#include <sys/cons.h> 12279697Snon#endif /* __FreeBSD__ */ 12367468Snon 12479697Snon/************************************************************** 12579697Snon * Constants 12679697Snon **************************************************************/ 12779697Snon#define SCSI_LOW_POLL_HZ 1000 12867468Snon 12979697Snon/* functions return values */ 13079697Snon#define SCSI_LOW_START_NO_QTAG 0 13179697Snon#define SCSI_LOW_START_QTAG 1 13279697Snon 13367468Snon#define SCSI_LOW_DONE_COMPLETE 0 13467468Snon#define SCSI_LOW_DONE_RETRY 1 13567468Snon 13679697Snon/* internal disk flags */ 13779697Snon#define SCSI_LOW_DISK_DISC 0x00000001 13879697Snon#define SCSI_LOW_DISK_QTAG 0x00000002 13979697Snon#define SCSI_LOW_DISK_LINK 0x00000004 14079697Snon#define SCSI_LOW_DISK_PARITY 0x00000008 14179697Snon#define SCSI_LOW_DISK_SYNC 0x00010000 14279697Snon#define SCSI_LOW_DISK_WIDE_16 0x00020000 14379697Snon#define SCSI_LOW_DISK_WIDE_32 0x00040000 14479697Snon#define SCSI_LOW_DISK_WIDE (SCSI_LOW_DISK_WIDE_16 | SCSI_LOW_DISK_WIDE_32) 14579697Snon#define SCSI_LOW_DISK_LFLAGS 0x0000ffff 14679697Snon#define SCSI_LOW_DISK_TFLAGS 0xffff0000 14779697Snon 148147723SavatarMALLOC_DEFINE(M_SCSILOW, "SCSI low", "SCSI low buffers"); 149147723Savatar 15079697Snon/************************************************************** 15179697Snon * Declarations 15279697Snon **************************************************************/ 15392770Salfred/* static */ void scsi_low_info(struct scsi_low_softc *, struct targ_info *, u_char *); 15492770Salfredstatic void scsi_low_engage(void *); 15592770Salfredstatic struct slccb *scsi_low_establish_ccb(struct targ_info *, struct lun_info *, scsi_low_tag_t); 15692770Salfredstatic int scsi_low_done(struct scsi_low_softc *, struct slccb *); 15792770Salfredstatic int scsi_low_setup_done(struct scsi_low_softc *, struct slccb *); 15892770Salfredstatic void scsi_low_bus_release(struct scsi_low_softc *, struct targ_info *); 15992770Salfredstatic void scsi_low_twiddle_wait(void); 16092770Salfredstatic struct lun_info *scsi_low_alloc_li(struct targ_info *, int, int); 16192770Salfredstatic struct targ_info *scsi_low_alloc_ti(struct scsi_low_softc *, int); 16292770Salfredstatic void scsi_low_calcf_lun(struct lun_info *); 16392770Salfredstatic void scsi_low_calcf_target(struct targ_info *); 16492770Salfredstatic void scsi_low_calcf_show(struct lun_info *); 16592770Salfredstatic void scsi_low_reset_nexus(struct scsi_low_softc *, int); 16692770Salfredstatic void scsi_low_reset_nexus_target(struct scsi_low_softc *, struct targ_info *, int); 16792770Salfredstatic void scsi_low_reset_nexus_lun(struct scsi_low_softc *, struct lun_info *, int); 16892770Salfredstatic int scsi_low_init(struct scsi_low_softc *, u_int); 16992770Salfredstatic void scsi_low_start(struct scsi_low_softc *); 17092770Salfredstatic void scsi_low_free_ti(struct scsi_low_softc *); 17167468Snon 17292770Salfredstatic int scsi_low_alloc_qtag(struct slccb *); 17392770Salfredstatic int scsi_low_dealloc_qtag(struct slccb *); 17492770Salfredstatic int scsi_low_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *, u_int, u_int); 17592770Salfredstatic int scsi_low_message_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, u_int); 17692770Salfredstatic void scsi_low_unit_ready_cmd(struct slccb *); 17792770Salfredstatic void scsi_low_timeout(void *); 17892770Salfredstatic int scsi_low_timeout_check(struct scsi_low_softc *); 17979697Snon#ifdef SCSI_LOW_START_UP_CHECK 18092770Salfredstatic int scsi_low_start_up(struct scsi_low_softc *); 18179697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 18292770Salfredstatic int scsi_low_abort_ccb(struct scsi_low_softc *, struct slccb *); 18392770Salfredstatic struct slccb *scsi_low_revoke_ccb(struct scsi_low_softc *, struct slccb *, int); 18479697Snon 18579697Snonint scsi_low_version_major = 2; 18679697Snonint scsi_low_version_minor = 17; 18779697Snon 18879697Snonstatic struct scsi_low_softc_tab sl_tab = LIST_HEAD_INITIALIZER(sl_tab); 18979697Snon 19079697Snon/************************************************************** 19179697Snon * Debug, Run test and Statics 19279697Snon **************************************************************/ 19379697Snon#ifdef SCSI_LOW_INFO_DETAIL 19479697Snon#define SCSI_LOW_INFO(slp, ti, s) scsi_low_info((slp), (ti), (s)) 19579697Snon#else /* !SCSI_LOW_INFO_DETAIL */ 19679697Snon#define SCSI_LOW_INFO(slp, ti, s) printf("%s: %s\n", (slp)->sl_xname, (s)) 19779697Snon#endif /* !SCSI_LOW_INFO_DETAIL */ 19879697Snon 19967468Snon#ifdef SCSI_LOW_STATICS 20089113Smsmithstatic struct scsi_low_statics { 20167468Snon int nexus_win; 20267468Snon int nexus_fail; 20367468Snon int nexus_disconnected; 20467468Snon int nexus_reselected; 20567468Snon int nexus_conflict; 20667468Snon} scsi_low_statics; 20767468Snon#endif /* SCSI_LOW_STATICS */ 20879697Snon 20979697Snon#ifdef SCSI_LOW_DEBUG 21079697Snon#define SCSI_LOW_DEBUG_DONE 0x00001 21179697Snon#define SCSI_LOW_DEBUG_DISC 0x00002 21279697Snon#define SCSI_LOW_DEBUG_SENSE 0x00004 21379697Snon#define SCSI_LOW_DEBUG_CALCF 0x00008 21479697Snon#define SCSI_LOW_DEBUG_ACTION 0x10000 21579697Snonint scsi_low_debug = 0; 21679697Snon 21779697Snon#define SCSI_LOW_MAX_ATTEN_CHECK 32 21879697Snon#define SCSI_LOW_ATTEN_CHECK 0x0001 21979697Snon#define SCSI_LOW_CMDLNK_CHECK 0x0002 22079697Snon#define SCSI_LOW_ABORT_CHECK 0x0004 22179697Snon#define SCSI_LOW_NEXUS_CHECK 0x0008 22279697Snonint scsi_low_test = 0; 22379697Snonint scsi_low_test_id = 0; 22479697Snon 22592770Salfredstatic void scsi_low_test_abort(struct scsi_low_softc *, struct targ_info *, struct lun_info *); 22692770Salfredstatic void scsi_low_test_cmdlnk(struct scsi_low_softc *, struct slccb *); 22792770Salfredstatic void scsi_low_test_atten(struct scsi_low_softc *, struct targ_info *, u_int); 22879697Snon#define SCSI_LOW_DEBUG_TEST_GO(fl, id) \ 22979697Snon ((scsi_low_test & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0) 23079697Snon#define SCSI_LOW_DEBUG_GO(fl, id) \ 23179697Snon ((scsi_low_debug & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0) 23279697Snon#endif /* SCSI_LOW_DEBUG */ 23379697Snon 23467468Snon/************************************************************** 23579697Snon * CCB 23679697Snon **************************************************************/ 23779697SnonGENERIC_CCB_STATIC_ALLOC(scsi_low, slccb) 23879697SnonGENERIC_CCB(scsi_low, slccb, ccb_chain) 23979697Snon 24079697Snon/************************************************************** 24179697Snon * Inline functions 24279697Snon **************************************************************/ 24379697Snon#define SCSI_LOW_INLINE static __inline 24492770SalfredSCSI_LOW_INLINE void scsi_low_activate_qtag(struct slccb *); 24592770SalfredSCSI_LOW_INLINE void scsi_low_deactivate_qtag(struct slccb *); 24692770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_assert(struct slccb *, u_int); 24792770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_exec(struct scsi_low_softc *, struct slccb *); 24892770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_retry(struct slccb *); 24992770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_clear(struct slccb *); 25092770SalfredSCSI_LOW_INLINE void scsi_low_init_msgsys(struct scsi_low_softc *, struct targ_info *); 25179697Snon 25279697SnonSCSI_LOW_INLINE void 25379697Snonscsi_low_activate_qtag(cb) 25479697Snon struct slccb *cb; 25579697Snon{ 25679697Snon struct lun_info *li = cb->li; 25779697Snon 25879697Snon if (cb->ccb_tag != SCSI_LOW_UNKTAG) 25979697Snon return; 26079697Snon 26179697Snon li->li_nqio ++; 26279697Snon cb->ccb_tag = cb->ccb_otag; 26379697Snon} 26479697Snon 26579697SnonSCSI_LOW_INLINE void 26679697Snonscsi_low_deactivate_qtag(cb) 26779697Snon struct slccb *cb; 26879697Snon{ 26979697Snon struct lun_info *li = cb->li; 27079697Snon 27179697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 27279697Snon return; 27379697Snon 27479697Snon li->li_nqio --; 27579697Snon cb->ccb_tag = SCSI_LOW_UNKTAG; 27679697Snon} 27779697Snon 27879697SnonSCSI_LOW_INLINE void 27979697Snonscsi_low_ccb_message_exec(slp, cb) 28079697Snon struct scsi_low_softc *slp; 28179697Snon struct slccb *cb; 28279697Snon{ 28379697Snon 28479697Snon scsi_low_assert_msg(slp, cb->ti, cb->ccb_msgoutflag, 0); 28579697Snon cb->ccb_msgoutflag = 0; 28679697Snon} 28779697Snon 28879697SnonSCSI_LOW_INLINE void 28979697Snonscsi_low_ccb_message_assert(cb, msg) 29079697Snon struct slccb *cb; 29179697Snon u_int msg; 29279697Snon{ 29379697Snon 29479697Snon cb->ccb_msgoutflag = cb->ccb_omsgoutflag = msg; 29579697Snon} 29679697Snon 29779697SnonSCSI_LOW_INLINE void 29879697Snonscsi_low_ccb_message_retry(cb) 29979697Snon struct slccb *cb; 30079697Snon{ 30179697Snon cb->ccb_msgoutflag = cb->ccb_omsgoutflag; 30279697Snon} 30379697Snon 30479697SnonSCSI_LOW_INLINE void 30579697Snonscsi_low_ccb_message_clear(cb) 30679697Snon struct slccb *cb; 30779697Snon{ 30879697Snon cb->ccb_msgoutflag = 0; 30979697Snon} 31079697Snon 31179697SnonSCSI_LOW_INLINE void 31279697Snonscsi_low_init_msgsys(slp, ti) 31379697Snon struct scsi_low_softc *slp; 31479697Snon struct targ_info *ti; 31579697Snon{ 31679697Snon 31779697Snon ti->ti_msginptr = 0; 31879697Snon ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0; 31979697Snon SCSI_LOW_DEASSERT_ATN(slp); 32079697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL); 32179697Snon} 32279697Snon 32379697Snon/*============================================================= 32479697Snon * START OF OS switch (All OS depend fucntions should be here) 32579697Snon =============================================================*/ 32679697Snon/* common os depend utitlities */ 32779697Snon#define SCSI_LOW_CMD_RESIDUAL_CHK 0x0001 32879697Snon#define SCSI_LOW_CMD_ORDERED_QTAG 0x0002 32979697Snon#define SCSI_LOW_CMD_ABORT_WARNING 0x0004 33079697Snon 33179697Snonstatic u_int8_t scsi_low_cmd_flags[256] = { 33279697Snon/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ 33379697Snon/*0*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0, 33479697Snon/*1*/ 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 33579697Snon/*2*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 5, 5, 33679697Snon/*3*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 33779697Snon}; 33879697Snon 33979697Snonstruct scsi_low_error_code { 34079697Snon int error_bits; 34179697Snon int error_code; 34279697Snon}; 34379697Snon 34492770Salfredstatic struct slccb *scsi_low_find_ccb(struct scsi_low_softc *, u_int, u_int, void *); 34592770Salfredstatic int scsi_low_translate_error_code(struct slccb *, struct scsi_low_error_code *); 34679697Snon 34779697Snonstatic struct slccb * 34879697Snonscsi_low_find_ccb(slp, target, lun, osdep) 34979697Snon struct scsi_low_softc *slp; 35079697Snon u_int target, lun; 35179697Snon void *osdep; 35279697Snon{ 35379697Snon struct targ_info *ti; 35479697Snon struct lun_info *li; 35579697Snon struct slccb *cb; 35679697Snon 35779697Snon ti = slp->sl_ti[target]; 35879697Snon li = scsi_low_alloc_li(ti, lun, 0); 35979697Snon if (li == NULL) 36079697Snon return NULL; 36179697Snon 36279697Snon if ((cb = slp->sl_Qnexus) != NULL && cb->osdep == osdep) 36379697Snon return cb; 36479697Snon 36579697Snon for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL; 36679697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 36779697Snon { 36879697Snon if (cb->osdep == osdep) 36979697Snon return cb; 37079697Snon } 37179697Snon 37279697Snon for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; 37379697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 37479697Snon { 37579697Snon if (cb->osdep == osdep) 37679697Snon return cb; 37779697Snon } 37879697Snon return NULL; 37979697Snon} 38079697Snon 38179697Snonstatic int 38279697Snonscsi_low_translate_error_code(cb, tp) 38379697Snon struct slccb *cb; 38479697Snon struct scsi_low_error_code *tp; 38579697Snon{ 38679697Snon 38779697Snon if (cb->ccb_error == 0) 38879697Snon return tp->error_code; 38979697Snon 39079697Snon for (tp ++; (cb->ccb_error & tp->error_bits) == 0; tp ++) 39179697Snon ; 39279697Snon return tp->error_code; 39379697Snon} 39479697Snon 39579697Snon#ifdef SCSI_LOW_INTERFACE_XS 39679697Snon/************************************************************** 39779697Snon * SCSI INTERFACE (XS) 39879697Snon **************************************************************/ 39979697Snon#define SCSI_LOW_MINPHYS 0x10000 400147723Savatar#define SCSI_LOW_MALLOC(size) malloc((size), M_SCSILOW, M_NOWAIT) 401147723Savatar#define SCSI_LOW_FREE(pt) free((pt), M_SCSILOW) 40279697Snon#define SCSI_LOW_ALLOC_CCB(flags) scsi_low_get_ccb((flags)) 40379697Snon#define SCSI_LOW_XS_POLL_HZ 1000 40479697Snon 40592770Salfredstatic int scsi_low_poll_xs(struct scsi_low_softc *, struct slccb *); 40692770Salfredstatic void scsi_low_scsi_minphys_xs(struct buf *); 40779697Snon#ifdef SCSI_LOW_TARGET_OPEN 40892770Salfredstatic int scsi_low_target_open(struct scsipi_link *, struct cfdata *); 40979697Snon#endif /* SCSI_LOW_TARGET_OPEN */ 41092770Salfredstatic int scsi_low_scsi_cmd_xs(struct scsipi_xfer *); 41192770Salfredstatic int scsi_low_enable_xs(void *, int); 41292770Salfredstatic int scsi_low_ioctl_xs(struct scsipi_link *, u_long, caddr_t, int, struct proc *); 41379697Snon 41492770Salfredstatic int scsi_low_attach_xs(struct scsi_low_softc *); 41592770Salfredstatic int scsi_low_world_start_xs(struct scsi_low_softc *); 41692770Salfredstatic int scsi_low_dettach_xs(struct scsi_low_softc *); 41792770Salfredstatic int scsi_low_ccb_setup_xs(struct scsi_low_softc *, struct slccb *); 41892770Salfredstatic int scsi_low_done_xs(struct scsi_low_softc *, struct slccb *); 41992770Salfredstatic void scsi_low_timeout_xs(struct scsi_low_softc *, int, int); 42092770Salfredstatic u_int scsi_low_translate_quirks_xs(u_int); 42192770Salfredstatic void scsi_low_setup_quirks_xs(struct targ_info *, struct lun_info *, u_int); 42279697Snon 42379697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_xs = { 42479697Snon scsi_low_attach_xs, 42579697Snon scsi_low_world_start_xs, 42679697Snon scsi_low_dettach_xs, 42779697Snon scsi_low_ccb_setup_xs, 42879697Snon scsi_low_done_xs, 42979697Snon scsi_low_timeout_xs 43079697Snon}; 43179697Snon 43279697Snonstruct scsipi_device scsi_low_dev = { 43379697Snon NULL, /* Use default error handler */ 43479697Snon NULL, /* have a queue, served by this */ 43579697Snon NULL, /* have no async handler */ 43679697Snon NULL, /* Use default 'done' routine */ 43779697Snon}; 43879697Snon 43979697Snonstruct scsi_low_error_code scsi_low_error_code_xs[] = { 44079697Snon {0, XS_NOERROR}, 44179697Snon {SENSEIO, XS_SENSE}, 44279697Snon {BUSYERR, XS_BUSY }, 44379697Snon {SELTIMEOUTIO, XS_SELTIMEOUT}, 44479697Snon {TIMEOUTIO, XS_TIMEOUT}, 44579697Snon {-1, XS_DRIVER_STUFFUP} 44679697Snon}; 44779697Snon 44879697Snonstatic int 44979697Snonscsi_low_ioctl_xs(link, cmd, addr, flag, p) 45079697Snon struct scsipi_link *link; 45179697Snon u_long cmd; 45279697Snon caddr_t addr; 45379697Snon int flag; 45479697Snon struct proc *p; 45579697Snon{ 45679697Snon struct scsi_low_softc *slp; 45779697Snon int s, error = ENOTTY; 45879697Snon 45979697Snon slp = (struct scsi_low_softc *) link->adapter_softc; 46079697Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 46179697Snon return ENXIO; 46279697Snon 46379697Snon if (cmd == SCBUSIORESET) 46479697Snon { 46579697Snon s = SCSI_LOW_SPLSCSI(); 46679697Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL); 46779697Snon splx(s); 46879697Snon error = 0; 46979697Snon } 47079697Snon else if (slp->sl_funcs->scsi_low_ioctl != 0) 47179697Snon { 47279697Snon error = (*slp->sl_funcs->scsi_low_ioctl) 47379697Snon (slp, cmd, addr, flag, p); 47479697Snon } 47579697Snon 47679697Snon return error; 47779697Snon} 47879697Snon 47979697Snonstatic int 48079697Snonscsi_low_enable_xs(arg, enable) 48179697Snon void *arg; 48279697Snon int enable; 48379697Snon{ 48479697Snon struct scsi_low_softc *slp = arg; 48579697Snon 48679697Snon if (enable != 0) 48779697Snon { 48879697Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 48979697Snon return ENXIO; 49079697Snon } 49179697Snon else 49279697Snon { 49379697Snon if ((slp->sl_flags & HW_INACTIVE) != 0 || 49479697Snon (slp->sl_flags & HW_POWERCTRL) == 0) 49579697Snon return 0; 49679697Snon 49779697Snon slp->sl_flags |= HW_POWDOWN; 49879697Snon if (slp->sl_funcs->scsi_low_power != NULL) 49979697Snon { 50079697Snon (*slp->sl_funcs->scsi_low_power) 50179697Snon (slp, SCSI_LOW_POWDOWN); 50279697Snon } 50379697Snon } 50479697Snon return 0; 50579697Snon} 50679697Snon 50779697Snonstatic void 50879697Snonscsi_low_scsi_minphys_xs(bp) 50979697Snon struct buf *bp; 51079697Snon{ 51179697Snon 51279697Snon if (bp->b_bcount > SCSI_LOW_MINPHYS) 51379697Snon bp->b_bcount = SCSI_LOW_MINPHYS; 51479697Snon minphys(bp); 51579697Snon} 51679697Snon 51779697Snonstatic int 51879697Snonscsi_low_poll_xs(slp, cb) 51979697Snon struct scsi_low_softc *slp; 52079697Snon struct slccb *cb; 52179697Snon{ 52279697Snon struct scsipi_xfer *xs = cb->osdep; 52379697Snon int tcount; 52479697Snon 52579697Snon cb->ccb_flags |= CCB_NOSDONE; 52679697Snon tcount = 0; 52779697Snon 52879697Snon while (slp->sl_nio > 0) 52979697Snon { 53079697Snon SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_XS_POLL_HZ); 53179697Snon 53279697Snon (*slp->sl_funcs->scsi_low_poll) (slp); 53379697Snon 53479697Snon if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0) 53579697Snon { 53679697Snon cb->ccb_flags |= CCB_NORETRY; 53779697Snon cb->ccb_error |= FATALIO; 53879697Snon (void) scsi_low_revoke_ccb(slp, cb, 1); 53979697Snon printf("%s: hardware inactive in poll mode\n", 54079697Snon slp->sl_xname); 54179697Snon } 54279697Snon 54379697Snon if ((xs->flags & ITSDONE) != 0) 54479697Snon break; 54579697Snon 54679697Snon if (tcount ++ < SCSI_LOW_XS_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) 54779697Snon continue; 54879697Snon 54979697Snon tcount = 0; 55079697Snon scsi_low_timeout_check(slp); 55179697Snon } 55279697Snon 55379697Snon xs->flags |= ITSDONE; 55479697Snon scsipi_done(xs); 55579697Snon return COMPLETE; 55679697Snon} 55779697Snon 55879697Snonstatic int 55979697Snonscsi_low_scsi_cmd_xs(xs) 56079697Snon struct scsipi_xfer *xs; 56179697Snon{ 56279697Snon struct scsipi_link *splp = xs->sc_link; 56379697Snon struct scsi_low_softc *slp = splp->adapter_softc; 56479697Snon struct targ_info *ti; 56579697Snon struct lun_info *li; 56679697Snon struct slccb *cb; 56779697Snon int s, targ, lun, flags, rv; 56879697Snon 56979697Snon if ((cb = SCSI_LOW_ALLOC_CCB(xs->flags & SCSI_NOSLEEP)) == NULL) 57079697Snon return TRY_AGAIN_LATER; 57179697Snon 57279697Snon targ = splp->scsipi_scsi.target, 57379697Snon lun = splp->scsipi_scsi.lun; 57479697Snon ti = slp->sl_ti[targ]; 57579697Snon 57679697Snon cb->osdep = xs; 57779697Snon cb->bp = xs->bp; 57879697Snon 57979697Snon if ((xs->flags & SCSI_POLL) == 0) 58079697Snon flags = CCB_AUTOSENSE; 58179697Snon else 58279697Snon flags = CCB_AUTOSENSE | CCB_POLLED; 58379697Snon 58479697Snon 58579697Snon s = SCSI_LOW_SPLSCSI(); 58679697Snon li = scsi_low_alloc_li(ti, lun, 1); 58779697Snon if ((u_int) splp->quirks != li->li_sloi.sloi_quirks) 58879697Snon { 58979697Snon scsi_low_setup_quirks_xs(ti, li, (u_int) splp->quirks); 59079697Snon } 59179697Snon 59279697Snon if ((xs->flags & SCSI_RESET) != 0) 59379697Snon { 59479697Snon flags |= CCB_NORETRY | CCB_URGENT; 59579697Snon scsi_low_enqueue(slp, ti, li, cb, flags, SCSI_LOW_MSG_RESET); 59679697Snon } 59779697Snon else 59879697Snon { 59979697Snon if (ti->ti_setup_msg != 0) 60079697Snon { 60179697Snon scsi_low_message_enqueue(slp, ti, li, flags); 60279697Snon } 60379697Snon 60479697Snon flags |= CCB_SCSIIO; 60579697Snon scsi_low_enqueue(slp, ti, li, cb, flags, 0); 60679697Snon } 60779697Snon 60879697Snon#ifdef SCSI_LOW_DEBUG 60979697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, ti->ti_id) != 0) 61079697Snon { 61179697Snon scsi_low_test_abort(slp, ti, li); 61279697Snon } 61379697Snon#endif /* SCSI_LOW_DEBUG */ 61479697Snon 61579697Snon if ((cb->ccb_flags & CCB_POLLED) != 0) 61679697Snon { 61779697Snon rv = scsi_low_poll_xs(slp, cb); 61879697Snon } 61979697Snon else 62079697Snon { 62179697Snon rv = SUCCESSFULLY_QUEUED; 62279697Snon } 62379697Snon splx(s); 62479697Snon return rv; 62579697Snon} 62679697Snon 62779697Snonstatic int 62879697Snonscsi_low_attach_xs(slp) 62979697Snon struct scsi_low_softc *slp; 63079697Snon{ 63179697Snon struct scsipi_adapter *sap; 63279697Snon struct scsipi_link *splp; 63379697Snon 63479697Snon strncpy(slp->sl_xname, slp->sl_dev.dv_xname, 16); 63579697Snon 63679697Snon sap = SCSI_LOW_MALLOC(sizeof(*sap)); 63779697Snon if (sap == NULL) 63879697Snon return ENOMEM; 63979697Snon splp = SCSI_LOW_MALLOC(sizeof(*splp)); 64079697Snon if (splp == NULL) 64179697Snon return ENOMEM; 64279697Snon 64379697Snon SCSI_LOW_BZERO(sap, sizeof(*sap)); 64479697Snon SCSI_LOW_BZERO(splp, sizeof(*splp)); 64579697Snon 64679697Snon sap->scsipi_cmd = scsi_low_scsi_cmd_xs; 64779697Snon sap->scsipi_minphys = scsi_low_scsi_minphys_xs; 64879697Snon sap->scsipi_enable = scsi_low_enable_xs; 64979697Snon sap->scsipi_ioctl = scsi_low_ioctl_xs; 65079697Snon#ifdef SCSI_LOW_TARGET_OPEN 65179697Snon sap->open_target_lu = scsi_low_target_open; 65279697Snon#endif /* SCSI_LOW_TARGET_OPEN */ 65379697Snon 65479697Snon splp->adapter_softc = slp; 65579697Snon splp->scsipi_scsi.adapter_target = slp->sl_hostid; 65679697Snon splp->scsipi_scsi.max_target = slp->sl_ntargs - 1; 65779697Snon splp->scsipi_scsi.max_lun = slp->sl_nluns - 1; 65879697Snon splp->scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE; 65979697Snon splp->openings = slp->sl_openings; 66079697Snon splp->type = BUS_SCSI; 66179697Snon splp->adapter_softc = slp; 66279697Snon splp->adapter = sap; 66379697Snon splp->device = &scsi_low_dev; 66479697Snon 66579697Snon slp->sl_si.si_splp = splp; 66679697Snon slp->sl_show_result = SHOW_ALL_NEG; 66779697Snon return 0; 66879697Snon} 66979697Snon 67079697Snonstatic int 67179697Snonscsi_low_world_start_xs(slp) 67279697Snon struct scsi_low_softc *slp; 67379697Snon{ 67479697Snon 67579697Snon return 0; 67679697Snon} 67779697Snon 67879697Snonstatic int 67979697Snonscsi_low_dettach_xs(slp) 68079697Snon struct scsi_low_softc *slp; 68179697Snon{ 68279697Snon 68379697Snon /* 68479697Snon * scsipi does not have dettach bus fucntion. 68579697Snon * 68679697Snon scsipi_dettach_scsibus(slp->sl_si.si_splp); 68779697Snon */ 68879697Snon return 0; 68979697Snon} 69079697Snon 69179697Snonstatic int 69279697Snonscsi_low_ccb_setup_xs(slp, cb) 69379697Snon struct scsi_low_softc *slp; 69479697Snon struct slccb *cb; 69579697Snon{ 69679697Snon struct scsipi_xfer *xs = (struct scsipi_xfer *) cb->osdep; 69779697Snon 69879697Snon if ((cb->ccb_flags & CCB_SCSIIO) != 0) 69979697Snon { 70079697Snon cb->ccb_scp.scp_cmd = (u_int8_t *) xs->cmd; 70179697Snon cb->ccb_scp.scp_cmdlen = xs->cmdlen; 70279697Snon cb->ccb_scp.scp_data = xs->data; 70379697Snon cb->ccb_scp.scp_datalen = xs->datalen; 70479697Snon cb->ccb_scp.scp_direction = (xs->flags & SCSI_DATA_OUT) ? 70579697Snon SCSI_LOW_WRITE : SCSI_LOW_READ; 70679697Snon cb->ccb_tcmax = xs->timeout / 1000; 70779697Snon } 70879697Snon else 70979697Snon { 71079697Snon scsi_low_unit_ready_cmd(cb); 71179697Snon } 71279697Snon return SCSI_LOW_START_QTAG; 71379697Snon} 71479697Snon 71579697Snonstatic int 71679697Snonscsi_low_done_xs(slp, cb) 71779697Snon struct scsi_low_softc *slp; 71879697Snon struct slccb *cb; 71979697Snon{ 72079697Snon struct scsipi_xfer *xs; 72179697Snon 72279697Snon xs = (struct scsipi_xfer *) cb->osdep; 72379697Snon if (cb->ccb_error == 0) 72479697Snon { 72579697Snon xs->error = XS_NOERROR; 72679697Snon xs->resid = 0; 72779697Snon } 72879697Snon else 72979697Snon { 73079697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 73179697Snon cb->ccb_error |= ABORTIO; 73279697Snon 73379697Snon if ((cb->ccb_flags & CCB_NORETRY) == 0 && 73479697Snon (cb->ccb_error & ABORTIO) == 0) 73579697Snon return EJUSTRETURN; 73679697Snon 73779697Snon if ((cb->ccb_error & SENSEIO) != 0) 73879697Snon { 73979697Snon xs->sense.scsi_sense = cb->ccb_sense; 74079697Snon } 74179697Snon 74279697Snon xs->error = scsi_low_translate_error_code(cb, 74379697Snon &scsi_low_error_code_xs[0]); 74479697Snon 74579697Snon#ifdef SCSI_LOW_DIAGNOSTIC 74679697Snon if ((cb->ccb_flags & CCB_SILENT) == 0 && 74779697Snon cb->ccb_scp.scp_cmdlen > 0 && 74879697Snon (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 74979697Snon SCSI_LOW_CMD_ABORT_WARNING) != 0) 75079697Snon { 75179697Snon printf("%s: WARNING: scsi_low IO abort\n", 75279697Snon slp->sl_xname); 75379697Snon scsi_low_print(slp, NULL); 75479697Snon } 75579697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 75679697Snon } 75779697Snon 75879697Snon if (cb->ccb_scp.scp_status == ST_UNKNOWN) 75979697Snon xs->status = 0; /* XXX */ 76079697Snon else 76179697Snon xs->status = cb->ccb_scp.scp_status; 76279697Snon 76379697Snon xs->flags |= ITSDONE; 76479697Snon if ((cb->ccb_flags & CCB_NOSDONE) == 0) 76579697Snon scsipi_done(xs); 76679697Snon 76779697Snon return 0; 76879697Snon} 76979697Snon 77079697Snonstatic void 77179697Snonscsi_low_timeout_xs(slp, ch, action) 77279697Snon struct scsi_low_softc *slp; 77379697Snon int ch; 77479697Snon int action; 77579697Snon{ 77679697Snon 77779697Snon switch (ch) 77879697Snon { 77979697Snon case SCSI_LOW_TIMEOUT_CH_IO: 78079697Snon switch (action) 78179697Snon { 78279697Snon case SCSI_LOW_TIMEOUT_START: 78379697Snon timeout(scsi_low_timeout, slp, 78479697Snon hz / SCSI_LOW_TIMEOUT_HZ); 78579697Snon break; 78679697Snon case SCSI_LOW_TIMEOUT_STOP: 78779697Snon untimeout(scsi_low_timeout, slp); 78879697Snon break; 78979697Snon } 79079697Snon break; 79179697Snon 79279697Snon case SCSI_LOW_TIMEOUT_CH_ENGAGE: 79379697Snon switch (action) 79479697Snon { 79579697Snon case SCSI_LOW_TIMEOUT_START: 79679697Snon timeout(scsi_low_engage, slp, 1); 79779697Snon break; 79879697Snon case SCSI_LOW_TIMEOUT_STOP: 79979697Snon untimeout(scsi_low_engage, slp); 80079697Snon break; 80179697Snon } 80279697Snon break; 80379697Snon 80479697Snon case SCSI_LOW_TIMEOUT_CH_RECOVER: 80579697Snon break; 80679697Snon } 80779697Snon} 80879697Snon 80979697Snonu_int 81079697Snonscsi_low_translate_quirks_xs(quirks) 81179697Snon u_int quirks; 81279697Snon{ 81379697Snon u_int flags; 81479697Snon 81579697Snon flags = SCSI_LOW_DISK_LFLAGS | SCSI_LOW_DISK_TFLAGS; 81679697Snon 81779697Snon#ifdef SDEV_NODISC 81879697Snon if (quirks & SDEV_NODISC) 81979697Snon flags &= ~SCSI_LOW_DISK_DISC; 82079697Snon#endif /* SDEV_NODISC */ 82179697Snon#ifdef SDEV_NOPARITY 82279697Snon if (quirks & SDEV_NOPARITY) 82379697Snon flags &= ~SCSI_LOW_DISK_PARITY; 82479697Snon#endif /* SDEV_NOPARITY */ 82579697Snon#ifdef SDEV_NOCMDLNK 82679697Snon if (quirks & SDEV_NOCMDLNK) 82779697Snon flags &= ~SCSI_LOW_DISK_LINK; 82879697Snon#endif /* SDEV_NOCMDLNK */ 82979697Snon#ifdef SDEV_NOTAG 83079697Snon if (quirks & SDEV_NOTAG) 83179697Snon flags &= ~SCSI_LOW_DISK_QTAG; 83279697Snon#endif /* SDEV_NOTAG */ 83379697Snon#ifdef SDEV_NOSYNC 83479697Snon if (quirks & SDEV_NOSYNC) 83579697Snon flags &= ~SCSI_LOW_DISK_SYNC; 83679697Snon#endif /* SDEV_NOSYNC */ 83779697Snon 83879697Snon return flags; 83979697Snon} 84079697Snon 84179697Snonstatic void 84279697Snonscsi_low_setup_quirks_xs(ti, li, flags) 84379697Snon struct targ_info *ti; 84479697Snon struct lun_info *li; 84579697Snon u_int flags; 84679697Snon{ 84779697Snon u_int quirks; 84879697Snon 84979697Snon li->li_sloi.sloi_quirks = flags; 85079697Snon quirks = scsi_low_translate_quirks_xs(flags); 85179697Snon ti->ti_quirks = quirks & SCSI_LOW_DISK_TFLAGS; 85279697Snon li->li_quirks = quirks & SCSI_LOW_DISK_LFLAGS; 85379697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 85479697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 85579697Snon scsi_low_calcf_target(ti); 85679697Snon scsi_low_calcf_lun(li); 85779697Snon scsi_low_calcf_show(li); 85879697Snon} 85979697Snon 86079697Snon#ifdef SCSI_LOW_TARGET_OPEN 86179697Snonstatic int 86279697Snonscsi_low_target_open(link, cf) 86379697Snon struct scsipi_link *link; 86479697Snon struct cfdata *cf; 86579697Snon{ 86679697Snon u_int target = link->scsipi_scsi.target; 86779697Snon u_int lun = link->scsipi_scsi.lun; 86879697Snon struct scsi_low_softc *slp; 86979697Snon struct targ_info *ti; 87079697Snon struct lun_info *li; 87179697Snon 87279697Snon slp = (struct scsi_low_softc *) link->adapter_softc; 87379697Snon ti = slp->sl_ti[target]; 87479697Snon li = scsi_low_alloc_li(ti, lun, 0); 87579697Snon if (li == NULL) 87679697Snon return 0; 87779697Snon 87879697Snon li->li_cfgflags = cf->cf_flags; 87979697Snon scsi_low_setup_quirks_xs(ti, li, (u_int) link->quirks); 88079697Snon return 0; 88179697Snon} 88279697Snon#endif /* SCSI_LOW_TARGET_OPEN */ 88379697Snon 88479697Snon#endif /* SCSI_LOW_INTERFACE_XS */ 88579697Snon 88679697Snon#ifdef SCSI_LOW_INTERFACE_CAM 88779697Snon/************************************************************** 88879697Snon * SCSI INTERFACE (CAM) 88979697Snon **************************************************************/ 890147723Savatar#define SCSI_LOW_MALLOC(size) malloc((size), M_SCSILOW, M_NOWAIT) 891147723Savatar#define SCSI_LOW_FREE(pt) free((pt), M_SCSILOW) 89279697Snon#define SCSI_LOW_ALLOC_CCB(flags) scsi_low_get_ccb() 89379697Snon 89492770Salfredstatic void scsi_low_poll_cam(struct cam_sim *); 89592770Salfredstatic void scsi_low_cam_rescan_callback(struct cam_periph *, union ccb *); 89692770Salfredstatic void scsi_low_rescan_bus_cam(struct scsi_low_softc *); 89792770Salfredvoid scsi_low_scsi_action_cam(struct cam_sim *, union ccb *); 89879697Snon 89992770Salfredstatic int scsi_low_attach_cam(struct scsi_low_softc *); 90092770Salfredstatic int scsi_low_world_start_cam(struct scsi_low_softc *); 90192770Salfredstatic int scsi_low_dettach_cam(struct scsi_low_softc *); 90292770Salfredstatic int scsi_low_ccb_setup_cam(struct scsi_low_softc *, struct slccb *); 90392770Salfredstatic int scsi_low_done_cam(struct scsi_low_softc *, struct slccb *); 90492770Salfredstatic void scsi_low_timeout_cam(struct scsi_low_softc *, int, int); 90579697Snon 90679697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_cam = { 90779697Snon scsi_low_attach_cam, 90879697Snon scsi_low_world_start_cam, 90979697Snon scsi_low_dettach_cam, 91079697Snon scsi_low_ccb_setup_cam, 91179697Snon scsi_low_done_cam, 91279697Snon scsi_low_timeout_cam 91379697Snon}; 91479697Snon 91579697Snonstruct scsi_low_error_code scsi_low_error_code_cam[] = { 91679697Snon {0, CAM_REQ_CMP}, 91779697Snon {SENSEIO, CAM_AUTOSNS_VALID | CAM_REQ_CMP_ERR}, 91879697Snon {SENSEERR, CAM_AUTOSENSE_FAIL}, 91979697Snon {UACAERR, CAM_SCSI_STATUS_ERROR}, 92079697Snon {BUSYERR | STATERR, CAM_SCSI_STATUS_ERROR}, 92179697Snon {SELTIMEOUTIO, CAM_SEL_TIMEOUT}, 92279697Snon {TIMEOUTIO, CAM_CMD_TIMEOUT}, 92379697Snon {PDMAERR, CAM_DATA_RUN_ERR}, 92479697Snon {PARITYERR, CAM_UNCOR_PARITY}, 92579697Snon {UBFERR, CAM_UNEXP_BUSFREE}, 92679697Snon {ABORTIO, CAM_REQ_ABORTED}, 92779697Snon {-1, CAM_UNREC_HBA_ERROR} 92879697Snon}; 92979697Snon 93079697Snon#define SIM2SLP(sim) ((struct scsi_low_softc *) cam_sim_softc((sim))) 93179697Snon 93279697Snon/* XXX: 93379697Snon * Please check a polling hz, currently we assume scsi_low_poll() is 93479697Snon * called each 1 ms. 93579697Snon */ 93679697Snon#define SCSI_LOW_CAM_POLL_HZ 1000 /* OK ? */ 93779697Snon 93879697Snonstatic void 93979697Snonscsi_low_poll_cam(sim) 94079697Snon struct cam_sim *sim; 94179697Snon{ 94279697Snon struct scsi_low_softc *slp = SIM2SLP(sim); 94379697Snon 94479697Snon (*slp->sl_funcs->scsi_low_poll) (slp); 94579697Snon 94679697Snon if (slp->sl_si.si_poll_count ++ >= 94779697Snon SCSI_LOW_CAM_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) 94879697Snon { 94979697Snon slp->sl_si.si_poll_count = 0; 95079697Snon scsi_low_timeout_check(slp); 95179697Snon } 95279697Snon} 95379697Snon 95479697Snonstatic void 95579697Snonscsi_low_cam_rescan_callback(periph, ccb) 95679697Snon struct cam_periph *periph; 95779697Snon union ccb *ccb; 95879697Snon{ 95979697Snon 96079697Snon xpt_free_path(ccb->ccb_h.path); 961147723Savatar xpt_free_ccb(ccb); 96279697Snon} 96379697Snon 96479697Snonstatic void 96579697Snonscsi_low_rescan_bus_cam(slp) 96679697Snon struct scsi_low_softc *slp; 96779697Snon{ 96879697Snon struct cam_path *path; 969147723Savatar union ccb *ccb = xpt_alloc_ccb(); 97079697Snon cam_status status; 97179697Snon 97279697Snon bzero(ccb, sizeof(union ccb)); 97379697Snon 97479697Snon status = xpt_create_path(&path, xpt_periph, 97579697Snon cam_sim_path(slp->sl_si.sim), -1, 0); 97679697Snon if (status != CAM_REQ_CMP) 97779697Snon return; 97879697Snon 97979697Snon xpt_setup_ccb(&ccb->ccb_h, path, 5); 98079697Snon ccb->ccb_h.func_code = XPT_SCAN_BUS; 98179697Snon ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback; 98279697Snon ccb->crcn.flags = CAM_FLAG_NONE; 98379697Snon xpt_action(ccb); 98479697Snon} 98579697Snon 98679697Snonvoid 98779697Snonscsi_low_scsi_action_cam(sim, ccb) 98879697Snon struct cam_sim *sim; 98979697Snon union ccb *ccb; 99079697Snon{ 99179697Snon struct scsi_low_softc *slp = SIM2SLP(sim); 99279697Snon struct targ_info *ti; 99379697Snon struct lun_info *li; 99479697Snon struct slccb *cb; 99579697Snon u_int lun, flags, msg, target; 99679697Snon int s, rv; 99779697Snon 99879697Snon target = (u_int) (ccb->ccb_h.target_id); 99979697Snon lun = (u_int) ccb->ccb_h.target_lun; 100079697Snon 100179697Snon#ifdef SCSI_LOW_DEBUG 100279697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_ACTION, target) != 0) 100379697Snon { 100479697Snon printf("%s: cam_action: func code 0x%x target: %d, lun: %d\n", 100579697Snon slp->sl_xname, ccb->ccb_h.func_code, target, lun); 100679697Snon } 100779697Snon#endif /* SCSI_LOW_DEBUG */ 100879697Snon 100979697Snon switch (ccb->ccb_h.func_code) { 101079697Snon case XPT_SCSI_IO: /* Execute the requested I/O operation */ 101179697Snon#ifdef SCSI_LOW_DIAGNOSTIC 101279697Snon if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD) 101379697Snon { 101479697Snon printf("%s: invalid target/lun\n", slp->sl_xname); 101579697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 101679697Snon xpt_done(ccb); 101779697Snon return; 101879697Snon } 101979697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 102079697Snon 102179697Snon if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) { 102279697Snon ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 102379697Snon xpt_done(ccb); 102479697Snon return; 102579697Snon } 102679697Snon 102779697Snon ti = slp->sl_ti[target]; 102879697Snon cb->osdep = ccb; 102979697Snon cb->bp = NULL; 103079697Snon if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) 103179697Snon flags = CCB_AUTOSENSE | CCB_SCSIIO; 103279697Snon else 103379697Snon flags = CCB_SCSIIO; 103479697Snon 103579697Snon s = SCSI_LOW_SPLSCSI(); 103679697Snon li = scsi_low_alloc_li(ti, lun, 1); 103779697Snon 103879697Snon if (ti->ti_setup_msg != 0) 103979697Snon { 104079697Snon scsi_low_message_enqueue(slp, ti, li, CCB_AUTOSENSE); 104179697Snon } 104279697Snon 104379697Snon scsi_low_enqueue(slp, ti, li, cb, flags, 0); 104479697Snon 104579697Snon#ifdef SCSI_LOW_DEBUG 104679697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, target) != 0) 104779697Snon { 104879697Snon scsi_low_test_abort(slp, ti, li); 104979697Snon } 105079697Snon#endif /* SCSI_LOW_DEBUG */ 105179697Snon splx(s); 105279697Snon break; 105379697Snon 105479697Snon case XPT_EN_LUN: /* Enable LUN as a target */ 105579697Snon case XPT_TARGET_IO: /* Execute target I/O request */ 105679697Snon case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 105779697Snon case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 105879697Snon /* XXX Implement */ 105979697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 106079697Snon xpt_done(ccb); 106179697Snon break; 106279697Snon 106379697Snon case XPT_ABORT: /* Abort the specified CCB */ 106479697Snon#ifdef SCSI_LOW_DIAGNOSTIC 106579697Snon if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD) 106679697Snon { 106779697Snon printf("%s: invalid target/lun\n", slp->sl_xname); 106879697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 106979697Snon xpt_done(ccb); 107079697Snon return; 107179697Snon } 107279697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 107379697Snon 107479697Snon s = SCSI_LOW_SPLSCSI(); 107579697Snon cb = scsi_low_find_ccb(slp, target, lun, ccb->cab.abort_ccb); 107679697Snon rv = scsi_low_abort_ccb(slp, cb); 107779697Snon splx(s); 107879697Snon 107979697Snon if (rv == 0) 108079697Snon ccb->ccb_h.status = CAM_REQ_CMP; 108179697Snon else 108279697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 108379697Snon xpt_done(ccb); 108479697Snon break; 108579697Snon 108679697Snon case XPT_SET_TRAN_SETTINGS: { 1087163816Smjacob#ifdef CAM_NEW_TRAN_CODE 1088163816Smjacob struct ccb_trans_settings_scsi *scsi; 1089163816Smjacob struct ccb_trans_settings_spi *spi; 1090163816Smjacob#endif 109179697Snon struct ccb_trans_settings *cts; 109279697Snon u_int val; 109379697Snon 109479697Snon#ifdef SCSI_LOW_DIAGNOSTIC 109579697Snon if (target == CAM_TARGET_WILDCARD) 109679697Snon { 109779697Snon printf("%s: invalid target\n", slp->sl_xname); 109879697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 109979697Snon xpt_done(ccb); 110079697Snon return; 110179697Snon } 110279697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 110379697Snon cts = &ccb->cts; 110479697Snon ti = slp->sl_ti[target]; 110579697Snon if (lun == CAM_LUN_WILDCARD) 110679697Snon lun = 0; 110779697Snon 110879697Snon s = SCSI_LOW_SPLSCSI(); 1109163816Smjacob#ifndef CAM_NEW_TRAN_CODE 111079697Snon if ((cts->valid & (CCB_TRANS_BUS_WIDTH_VALID | 111179697Snon CCB_TRANS_SYNC_RATE_VALID | 111279697Snon CCB_TRANS_SYNC_OFFSET_VALID)) != 0) 111379697Snon { 111479697Snon if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { 111579697Snon val = cts->bus_width; 111679697Snon if (val < ti->ti_width) 111779697Snon ti->ti_width = val; 111879697Snon } 111979697Snon if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) { 112079697Snon val = cts->sync_period; 112179697Snon if (val == 0 || val > ti->ti_maxsynch.period) 112279697Snon ti->ti_maxsynch.period = val; 112379697Snon } 112479697Snon if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) { 112579697Snon val = cts->sync_offset; 112679697Snon if (val < ti->ti_maxsynch.offset) 112779697Snon ti->ti_maxsynch.offset = val; 112879697Snon } 112979697Snon 113079697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 113179697Snon scsi_low_calcf_target(ti); 113279697Snon } 113379697Snon 113479697Snon if ((cts->valid & (CCB_TRANS_DISC_VALID | 113579697Snon CCB_TRANS_TQ_VALID)) != 0) 113679697Snon { 113779697Snon li = scsi_low_alloc_li(ti, lun, 1); 113879697Snon if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) 113979697Snon { 114079697Snon if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 114179697Snon li->li_quirks |= SCSI_LOW_DISK_DISC; 114279697Snon else 114379697Snon li->li_quirks &= ~SCSI_LOW_DISK_DISC; 114479697Snon } 114579697Snon if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) 114679697Snon { 114779697Snon if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 114879697Snon li->li_quirks |= SCSI_LOW_DISK_QTAG; 114979697Snon else 115079697Snon li->li_quirks &= ~SCSI_LOW_DISK_QTAG; 115179697Snon } 115279697Snon 115379697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 115479697Snon scsi_low_calcf_target(ti); 115579697Snon scsi_low_calcf_lun(li); 115679697Snon if ((slp->sl_show_result & SHOW_CALCF_RES) != 0) 115779697Snon scsi_low_calcf_show(li); 115879697Snon } 1159163816Smjacob#else 1160163816Smjacob scsi = &cts->proto_specific.scsi; 1161163816Smjacob spi = &cts->xport_specific.spi; 1162163816Smjacob if ((spi->valid & (CTS_SPI_VALID_BUS_WIDTH | 1163163816Smjacob CTS_SPI_VALID_SYNC_RATE | 1164163816Smjacob CTS_SPI_VALID_SYNC_OFFSET)) != 0) 1165163816Smjacob { 1166163816Smjacob if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) { 1167163816Smjacob val = spi->bus_width; 1168163816Smjacob if (val < ti->ti_width) 1169163816Smjacob ti->ti_width = val; 1170163816Smjacob } 1171163816Smjacob if (spi->valid & CTS_SPI_VALID_SYNC_RATE) { 1172163816Smjacob val = spi->sync_period; 1173163816Smjacob if (val == 0 || val > ti->ti_maxsynch.period) 1174163816Smjacob ti->ti_maxsynch.period = val; 1175163816Smjacob } 1176163816Smjacob if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) { 1177163816Smjacob val = spi->sync_offset; 1178163816Smjacob if (val < ti->ti_maxsynch.offset) 1179163816Smjacob ti->ti_maxsynch.offset = val; 1180163816Smjacob } 1181163816Smjacob ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 1182163816Smjacob scsi_low_calcf_target(ti); 1183163816Smjacob } 1184163816Smjacob 1185163816Smjacob if ((spi->valid & CTS_SPI_FLAGS_DISC_ENB) != 0 || 1186163816Smjacob (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { 1187163816Smjacob 1188163816Smjacob li = scsi_low_alloc_li(ti, lun, 1); 1189163816Smjacob if (spi->valid & CTS_SPI_FLAGS_DISC_ENB) { 1190163816Smjacob li->li_quirks |= SCSI_LOW_DISK_DISC; 1191163816Smjacob } else { 1192163816Smjacob li->li_quirks &= ~SCSI_LOW_DISK_DISC; 1193163816Smjacob } 1194163816Smjacob 1195163816Smjacob if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) { 1196163816Smjacob li->li_quirks |= SCSI_LOW_DISK_QTAG; 1197163816Smjacob } else { 1198163816Smjacob li->li_quirks &= ~SCSI_LOW_DISK_QTAG; 1199163816Smjacob } 1200163816Smjacob li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 1201163816Smjacob scsi_low_calcf_target(ti); 1202163816Smjacob scsi_low_calcf_lun(li); 1203163816Smjacob if ((slp->sl_show_result & SHOW_CALCF_RES) != 0) 1204163816Smjacob scsi_low_calcf_show(li); 1205163816Smjacob } 1206163816Smjacob#endif 120779697Snon splx(s); 120879697Snon 120979697Snon ccb->ccb_h.status = CAM_REQ_CMP; 121079697Snon xpt_done(ccb); 121179697Snon break; 121279697Snon } 121379697Snon 121479697Snon case XPT_GET_TRAN_SETTINGS: { 121579697Snon struct ccb_trans_settings *cts; 121679697Snon u_int diskflags; 121779697Snon 121879697Snon cts = &ccb->cts; 121979697Snon#ifdef SCSI_LOW_DIAGNOSTIC 122079697Snon if (target == CAM_TARGET_WILDCARD) 122179697Snon { 122279697Snon printf("%s: invalid target\n", slp->sl_xname); 122379697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 122479697Snon xpt_done(ccb); 122579697Snon return; 122679697Snon } 122779697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 122879697Snon ti = slp->sl_ti[target]; 122979697Snon if (lun == CAM_LUN_WILDCARD) 123079697Snon lun = 0; 123179697Snon 123279697Snon s = SCSI_LOW_SPLSCSI(); 123379697Snon li = scsi_low_alloc_li(ti, lun, 1); 123479697Snon#ifdef CAM_NEW_TRAN_CODE 123579697Snon if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) { 123679697Snon struct ccb_trans_settings_scsi *scsi = 123779697Snon &cts->proto_specific.scsi; 123879697Snon struct ccb_trans_settings_spi *spi = 123979697Snon &cts->xport_specific.spi; 124079697Snon#ifdef SCSI_LOW_DIAGNOSTIC 124179697Snon if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID) 124279697Snon { 124379697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 124479697Snon printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n", 124579697Snon slp->sl_xname); 124679697Snon goto settings_out; 124779697Snon } 124879697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 124979697Snon cts->protocol = PROTO_SCSI; 125079697Snon cts->protocol_version = SCSI_REV_2; 125179697Snon cts->transport = XPORT_SPI; 125279697Snon cts->transport_version = 2; 125379697Snon 125479697Snon scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 125579697Snon spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 125679697Snon 125779697Snon diskflags = li->li_diskflags & li->li_cfgflags; 125879697Snon if (diskflags & SCSI_LOW_DISK_DISC) 125979697Snon spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 126079697Snon if (diskflags & SCSI_LOW_DISK_QTAG) 126179697Snon scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 126279697Snon 126379697Snon spi->sync_period = ti->ti_maxsynch.period; 126479697Snon spi->valid |= CTS_SPI_VALID_SYNC_RATE; 126579697Snon spi->sync_offset = ti->ti_maxsynch.offset; 126679697Snon spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 126779697Snon 126879697Snon spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 126979697Snon spi->bus_width = ti->ti_width; 127079697Snon 127179697Snon if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 127279697Snon scsi->valid = CTS_SCSI_VALID_TQ; 127379697Snon spi->valid |= CTS_SPI_VALID_DISC; 127479697Snon } else 127579697Snon scsi->valid = 0; 127679697Snon } else 127779697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 127879697Snon#else 127979697Snon if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) 128079697Snon { 128179697Snon#ifdef SCSI_LOW_DIAGNOSTIC 128279697Snon if ((li->li_flags_valid & SCSI_LOW_LUN_FLAGS_DISK_VALID) == 0) 128379697Snon { 128479697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 128579697Snon printf("%s: invalid GET_TRANS_USER_SETTINGS call\n", 128679697Snon slp->sl_xname); 128779697Snon goto settings_out; 128879697Snon } 128979697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 129079697Snon diskflags = li->li_diskflags & li->li_cfgflags; 129179697Snon if ((diskflags & SCSI_LOW_DISK_DISC) != 0) 129279697Snon cts->flags |= CCB_TRANS_DISC_ENB; 129379697Snon else 129479697Snon cts->flags &= ~CCB_TRANS_DISC_ENB; 129579697Snon if ((diskflags & SCSI_LOW_DISK_QTAG) != 0) 129679697Snon cts->flags |= CCB_TRANS_TAG_ENB; 129779697Snon else 129879697Snon cts->flags &= ~CCB_TRANS_TAG_ENB; 129979697Snon } 130079697Snon else if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) 130179697Snon { 130279697Snon#ifdef SCSI_LOW_DIAGNOSTIC 130379697Snon if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID) 130479697Snon { 130579697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 130679697Snon printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n", 130779697Snon slp->sl_xname); 130879697Snon goto settings_out; 130979697Snon } 131079697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 131179697Snon if ((li->li_flags & SCSI_LOW_DISC) != 0) 131279697Snon cts->flags |= CCB_TRANS_DISC_ENB; 131379697Snon else 131479697Snon cts->flags &= ~CCB_TRANS_DISC_ENB; 131579697Snon if ((li->li_flags & SCSI_LOW_QTAG) != 0) 131679697Snon cts->flags |= CCB_TRANS_TAG_ENB; 131779697Snon else 131879697Snon cts->flags &= ~CCB_TRANS_TAG_ENB; 131979697Snon } 132079697Snon else 132179697Snon { 132279697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 132379697Snon goto settings_out; 132479697Snon } 132579697Snon 132679697Snon cts->sync_period = ti->ti_maxsynch.period; 132779697Snon cts->sync_offset = ti->ti_maxsynch.offset; 132879697Snon cts->bus_width = ti->ti_width; 132979697Snon 133079697Snon cts->valid = CCB_TRANS_SYNC_RATE_VALID 133179697Snon | CCB_TRANS_SYNC_OFFSET_VALID 133279697Snon | CCB_TRANS_BUS_WIDTH_VALID 133379697Snon | CCB_TRANS_DISC_VALID 133479697Snon | CCB_TRANS_TQ_VALID; 133579697Snon ccb->ccb_h.status = CAM_REQ_CMP; 133679697Snon#endif 133779697Snonsettings_out: 133879697Snon splx(s); 133979697Snon xpt_done(ccb); 134079697Snon break; 134179697Snon } 134279697Snon 134379697Snon case XPT_CALC_GEOMETRY: { /* not yet HN2 */ 1344116351Snjl cam_calc_geometry(&ccb->ccg, /*extended*/1); 134579697Snon xpt_done(ccb); 134679697Snon break; 134779697Snon } 134879697Snon 134979697Snon case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 135079697Snon s = SCSI_LOW_SPLSCSI(); 135179697Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL); 135279697Snon splx(s); 135379697Snon ccb->ccb_h.status = CAM_REQ_CMP; 135479697Snon xpt_done(ccb); 135579697Snon break; 135679697Snon 135779697Snon case XPT_TERM_IO: /* Terminate the I/O process */ 135879697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 135979697Snon xpt_done(ccb); 136079697Snon break; 136179697Snon 136279697Snon case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 136379697Snon#ifdef SCSI_LOW_DIAGNOSTIC 136479697Snon if (target == CAM_TARGET_WILDCARD) 136579697Snon { 136679697Snon printf("%s: invalid target\n", slp->sl_xname); 136779697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 136879697Snon xpt_done(ccb); 136979697Snon return; 137079697Snon } 137179697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 137279697Snon 137379697Snon msg = SCSI_LOW_MSG_RESET; 137479697Snon if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) 137579697Snon { 137679697Snon ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 137779697Snon xpt_done(ccb); 137879697Snon return; 137979697Snon } 138079697Snon 138179697Snon ti = slp->sl_ti[target]; 138279697Snon if (lun == CAM_LUN_WILDCARD) 138379697Snon lun = 0; 138479697Snon cb->osdep = ccb; 138579697Snon cb->bp = NULL; 138679697Snon if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) 138779697Snon flags = CCB_AUTOSENSE | CCB_NORETRY | CCB_URGENT; 138879697Snon else 138979697Snon flags = CCB_NORETRY | CCB_URGENT; 139079697Snon 139179697Snon s = SCSI_LOW_SPLSCSI(); 139279697Snon li = scsi_low_alloc_li(ti, lun, 1); 139379697Snon scsi_low_enqueue(slp, ti, li, cb, flags, msg); 139479697Snon splx(s); 139579697Snon break; 139679697Snon 139779697Snon case XPT_PATH_INQ: { /* Path routing inquiry */ 139879697Snon struct ccb_pathinq *cpi = &ccb->cpi; 139979697Snon 140079697Snon cpi->version_num = scsi_low_version_major; 140179697Snon cpi->hba_inquiry = PI_TAG_ABLE | PI_LINKED_CDB; 140279697Snon ti = slp->sl_ti[slp->sl_hostid]; /* host id */ 140379697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 140479697Snon cpi->hba_inquiry |= PI_WIDE_16; 140579697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_16) 140679697Snon cpi->hba_inquiry |= PI_WIDE_32; 140779697Snon if (ti->ti_maxsynch.offset > 0) 140879697Snon cpi->hba_inquiry |= PI_SDTR_ABLE; 140979697Snon cpi->target_sprt = 0; 141079697Snon cpi->hba_misc = 0; 141179697Snon cpi->hba_eng_cnt = 0; 141279697Snon cpi->max_target = slp->sl_ntargs - 1; 141379697Snon cpi->max_lun = slp->sl_nluns - 1; 141479697Snon cpi->initiator_id = slp->sl_hostid; 141579697Snon cpi->bus_id = cam_sim_bus(sim); 141679697Snon cpi->base_transfer_speed = 3300; 141779697Snon#ifdef CAM_NEW_TRAN_CODE 141879697Snon cpi->transport = XPORT_SPI; 141979697Snon cpi->transport_version = 2; 142079697Snon cpi->protocol = PROTO_SCSI; 142179697Snon cpi->protocol_version = SCSI_REV_2; 142279697Snon#endif 142379697Snon strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 142479697Snon strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN); 142579697Snon strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 142679697Snon cpi->unit_number = cam_sim_unit(sim); 142779697Snon cpi->ccb_h.status = CAM_REQ_CMP; 142879697Snon xpt_done(ccb); 142979697Snon break; 143079697Snon } 143179697Snon 143279697Snon default: 143379697Snon printf("scsi_low: non support func_code = %d ", 143479697Snon ccb->ccb_h.func_code); 143579697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 143679697Snon xpt_done(ccb); 143779697Snon break; 143879697Snon } 143979697Snon} 144079697Snon 144179697Snonstatic int 144279697Snonscsi_low_attach_cam(slp) 144379697Snon struct scsi_low_softc *slp; 144479697Snon{ 144579697Snon struct cam_devq *devq; 144679697Snon int tagged_openings; 144779697Snon 144879697Snon sprintf(slp->sl_xname, "%s%d", 144979697Snon DEVPORT_DEVNAME(slp->sl_dev), DEVPORT_DEVUNIT(slp->sl_dev)); 145079697Snon 145179697Snon devq = cam_simq_alloc(SCSI_LOW_NCCB); 145279697Snon if (devq == NULL) 145379697Snon return (ENOMEM); 145479697Snon 145579697Snon /* 145679697Snon * ask the adapter what subunits are present 145779697Snon */ 145879697Snon tagged_openings = min(slp->sl_openings, SCSI_LOW_MAXNEXUS); 145979697Snon slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam, 146079697Snon scsi_low_poll_cam, 146179697Snon DEVPORT_DEVNAME(slp->sl_dev), slp, 146279697Snon DEVPORT_DEVUNIT(slp->sl_dev), 146379697Snon slp->sl_openings, tagged_openings, devq); 146479697Snon 146579697Snon if (slp->sl_si.sim == NULL) { 146679697Snon cam_simq_free(devq); 146779697Snon return ENODEV; 146879697Snon } 146979697Snon 147079697Snon if (xpt_bus_register(slp->sl_si.sim, 0) != CAM_SUCCESS) { 1471147723Savatar free(slp->sl_si.sim, M_SCSILOW); 147279697Snon return ENODEV; 147379697Snon } 147479697Snon 147579697Snon if (xpt_create_path(&slp->sl_si.path, /*periph*/NULL, 147679697Snon cam_sim_path(slp->sl_si.sim), CAM_TARGET_WILDCARD, 147779697Snon CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 147879697Snon xpt_bus_deregister(cam_sim_path(slp->sl_si.sim)); 147979697Snon cam_sim_free(slp->sl_si.sim, /*free_simq*/TRUE); 148079697Snon return ENODEV; 148179697Snon } 148279697Snon 148379697Snon slp->sl_show_result = SHOW_CALCF_RES; /* OK ? */ 148479697Snon return 0; 148579697Snon} 148679697Snon 148779697Snonstatic int 148879697Snonscsi_low_world_start_cam(slp) 148979697Snon struct scsi_low_softc *slp; 149079697Snon{ 149179697Snon 149279697Snon if (!cold) 149379697Snon scsi_low_rescan_bus_cam(slp); 149479697Snon return 0; 149579697Snon} 149679697Snon 149779697Snonstatic int 149879697Snonscsi_low_dettach_cam(slp) 149979697Snon struct scsi_low_softc *slp; 150079697Snon{ 150179697Snon 150279697Snon xpt_async(AC_LOST_DEVICE, slp->sl_si.path, NULL); 150379697Snon xpt_free_path(slp->sl_si.path); 150479697Snon xpt_bus_deregister(cam_sim_path(slp->sl_si.sim)); 150579697Snon cam_sim_free(slp->sl_si.sim, /* free_devq */ TRUE); 150679697Snon return 0; 150779697Snon} 150879697Snon 150979697Snonstatic int 151079697Snonscsi_low_ccb_setup_cam(slp, cb) 151179697Snon struct scsi_low_softc *slp; 151279697Snon struct slccb *cb; 151379697Snon{ 151479697Snon union ccb *ccb = (union ccb *) cb->osdep; 151579697Snon 151679697Snon if ((cb->ccb_flags & CCB_SCSIIO) != 0) 151779697Snon { 151879697Snon cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes; 151979697Snon cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len; 152079697Snon cb->ccb_scp.scp_data = ccb->csio.data_ptr; 152179697Snon cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len; 152279697Snon if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 152379697Snon cb->ccb_scp.scp_direction = SCSI_LOW_WRITE; 152479697Snon else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */ 152579697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 152679697Snon cb->ccb_tcmax = ccb->ccb_h.timeout / 1000; 152779697Snon } 152879697Snon else 152979697Snon { 153079697Snon scsi_low_unit_ready_cmd(cb); 153179697Snon } 153279697Snon return SCSI_LOW_START_QTAG; 153379697Snon} 153479697Snon 153579697Snonstatic int 153679697Snonscsi_low_done_cam(slp, cb) 153779697Snon struct scsi_low_softc *slp; 153879697Snon struct slccb *cb; 153979697Snon{ 154079697Snon union ccb *ccb; 154179697Snon 154279697Snon ccb = (union ccb *) cb->osdep; 154379697Snon if (cb->ccb_error == 0) 154479697Snon { 154579697Snon ccb->ccb_h.status = CAM_REQ_CMP; 154679697Snon ccb->csio.resid = 0; 154779697Snon } 154879697Snon else 154979697Snon { 155079697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 155179697Snon cb->ccb_error |= ABORTIO; 155279697Snon 155379697Snon if ((cb->ccb_flags & CCB_NORETRY) == 0 && 155479697Snon (cb->ccb_error & ABORTIO) == 0) 155579697Snon return EJUSTRETURN; 155679697Snon 155779697Snon if ((cb->ccb_error & SENSEIO) != 0) 155879697Snon { 155979697Snon memcpy(&ccb->csio.sense_data, 156079697Snon &cb->ccb_sense, 156179697Snon sizeof(ccb->csio.sense_data)); 156279697Snon } 156379697Snon 156479697Snon ccb->ccb_h.status = scsi_low_translate_error_code(cb, 156579697Snon &scsi_low_error_code_cam[0]); 156679697Snon 156779697Snon#ifdef SCSI_LOW_DIAGNOSTIC 156879697Snon if ((cb->ccb_flags & CCB_SILENT) == 0 && 156979697Snon cb->ccb_scp.scp_cmdlen > 0 && 157079697Snon (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 157179697Snon SCSI_LOW_CMD_ABORT_WARNING) != 0) 157279697Snon { 157379697Snon printf("%s: WARNING: scsi_low IO abort\n", 157479697Snon slp->sl_xname); 157579697Snon scsi_low_print(slp, NULL); 157679697Snon } 157779697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 157879697Snon } 157979697Snon 158079697Snon if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0) 158179697Snon ccb->ccb_h.status |= CAM_REQ_CMP_ERR; 158279697Snon 158379697Snon if (cb->ccb_scp.scp_status == ST_UNKNOWN) 158479697Snon ccb->csio.scsi_status = 0; /* XXX */ 158579697Snon else 158679697Snon ccb->csio.scsi_status = cb->ccb_scp.scp_status; 158779697Snon 158879697Snon if ((cb->ccb_flags & CCB_NOSDONE) == 0) 158979697Snon xpt_done(ccb); 159079697Snon return 0; 159179697Snon} 159279697Snon 159379697Snonstatic void 159479697Snonscsi_low_timeout_cam(slp, ch, action) 159579697Snon struct scsi_low_softc *slp; 159679697Snon int ch; 159779697Snon int action; 159879697Snon{ 159979697Snon 160079697Snon switch (ch) 160179697Snon { 160279697Snon case SCSI_LOW_TIMEOUT_CH_IO: 160379697Snon switch (action) 160479697Snon { 160579697Snon case SCSI_LOW_TIMEOUT_START: 160679697Snon slp->sl_si.timeout_ch = timeout(scsi_low_timeout, slp, 160779697Snon hz / SCSI_LOW_TIMEOUT_HZ); 160879697Snon break; 160979697Snon case SCSI_LOW_TIMEOUT_STOP: 161079697Snon untimeout(scsi_low_timeout, slp, slp->sl_si.timeout_ch); 161179697Snon break; 161279697Snon } 161379697Snon break; 161479697Snon 161579697Snon case SCSI_LOW_TIMEOUT_CH_ENGAGE: 161679697Snon switch (action) 161779697Snon { 161879697Snon case SCSI_LOW_TIMEOUT_START: 161979697Snon slp->sl_si.engage_ch = timeout(scsi_low_engage, slp, 1); 162079697Snon break; 162179697Snon case SCSI_LOW_TIMEOUT_STOP: 162279697Snon untimeout(scsi_low_engage, slp, slp->sl_si.engage_ch); 162379697Snon break; 162479697Snon } 162579697Snon break; 162679697Snon case SCSI_LOW_TIMEOUT_CH_RECOVER: 162779697Snon break; 162879697Snon } 162979697Snon} 163079697Snon 163179697Snon#endif /* SCSI_LOW_INTERFACE_CAM */ 163279697Snon 163379697Snon/*============================================================= 163479697Snon * END OF OS switch (All OS depend fucntions should be above) 163579697Snon =============================================================*/ 163679697Snon 163779697Snon/************************************************************** 163879697Snon * scsi low deactivate and activate 163979697Snon **************************************************************/ 164079697Snonint 164179697Snonscsi_low_is_busy(slp) 164279697Snon struct scsi_low_softc *slp; 164379697Snon{ 164479697Snon 164579697Snon if (slp->sl_nio > 0) 164679697Snon return EBUSY; 164779697Snon return 0; 164879697Snon} 164979697Snon 165079697Snonint 165179697Snonscsi_low_deactivate(slp) 165279697Snon struct scsi_low_softc *slp; 165379697Snon{ 165479697Snon int s; 165579697Snon 165679697Snon s = SCSI_LOW_SPLSCSI(); 165779697Snon slp->sl_flags |= HW_INACTIVE; 165879697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 165979697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_STOP); 166079697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 166179697Snon (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP); 166279697Snon splx(s); 166379697Snon return 0; 166479697Snon} 166579697Snon 166679697Snonint 166779697Snonscsi_low_activate(slp) 166879697Snon struct scsi_low_softc *slp; 166979697Snon{ 167079697Snon int error, s; 167179697Snon 167279697Snon s = SCSI_LOW_SPLSCSI(); 167379697Snon slp->sl_flags &= ~HW_INACTIVE; 167479697Snon if ((error = scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL)) != 0) 167579697Snon { 167679697Snon slp->sl_flags |= HW_INACTIVE; 167779697Snon splx(s); 167879697Snon return error; 167979697Snon } 168079697Snon 168179697Snon slp->sl_timeout_count = 0; 168279697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 168379697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 168479697Snon splx(s); 168579697Snon return 0; 168679697Snon} 168779697Snon 168879697Snon/************************************************************** 168979697Snon * scsi low log 169079697Snon **************************************************************/ 169179697Snon#ifdef SCSI_LOW_DIAGNOSTIC 169292770Salfredstatic void scsi_low_msg_log_init(struct scsi_low_msg_log *); 169392770Salfredstatic void scsi_low_msg_log_write(struct scsi_low_msg_log *, u_int8_t *, int); 169492770Salfredstatic void scsi_low_msg_log_show(struct scsi_low_msg_log *, char *, int); 169579697Snon 169679697Snonstatic void 169779697Snonscsi_low_msg_log_init(slmlp) 169879697Snon struct scsi_low_msg_log *slmlp; 169979697Snon{ 170079697Snon 170179697Snon slmlp->slml_ptr = 0; 170279697Snon} 170379697Snon 170479697Snonstatic void 170579697Snonscsi_low_msg_log_write(slmlp, datap, len) 170679697Snon struct scsi_low_msg_log *slmlp; 170779697Snon u_int8_t *datap; 170879697Snon int len; 170979697Snon{ 171079697Snon int ptr, ind; 171179697Snon 171279697Snon if (slmlp->slml_ptr >= SCSI_LOW_MSG_LOG_DATALEN) 171379697Snon return; 171479697Snon 171579697Snon ptr = slmlp->slml_ptr ++; 171679697Snon for (ind = 0; ind < sizeof(slmlp->slml_msg[0]) && ind < len; ind ++) 171779697Snon slmlp->slml_msg[ptr].msg[ind] = datap[ind]; 171879697Snon for ( ; ind < sizeof(slmlp->slml_msg[0]); ind ++) 171979697Snon slmlp->slml_msg[ptr].msg[ind] = 0; 172079697Snon} 172179697Snon 172279697Snonstatic void 172379697Snonscsi_low_msg_log_show(slmlp, s, len) 172479697Snon struct scsi_low_msg_log *slmlp; 172579697Snon char *s; 172679697Snon int len; 172779697Snon{ 172879697Snon int ptr, ind; 172979697Snon 173079697Snon printf("%s: (%d) ", s, slmlp->slml_ptr); 173179697Snon for (ptr = 0; ptr < slmlp->slml_ptr; ptr ++) 173279697Snon { 173379697Snon for (ind = 0; ind < len && ind < sizeof(slmlp->slml_msg[0]); 173479697Snon ind ++) 173579697Snon { 173679697Snon printf("[%x]", (u_int) slmlp->slml_msg[ptr].msg[ind]); 173779697Snon } 173879697Snon printf(">"); 173979697Snon } 174079697Snon printf("\n"); 174179697Snon} 174279697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 174379697Snon 174479697Snon/************************************************************** 174567468Snon * power control 174667468Snon **************************************************************/ 174767468Snonstatic void 174867468Snonscsi_low_engage(arg) 174967468Snon void *arg; 175067468Snon{ 175167468Snon struct scsi_low_softc *slp = arg; 175279697Snon int s = SCSI_LOW_SPLSCSI(); 175367468Snon 175467468Snon switch (slp->sl_rstep) 175567468Snon { 175667468Snon case 0: 175767468Snon slp->sl_rstep ++; 175867468Snon (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); 175979697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp, 176079697Snon SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_START); 176167468Snon break; 176267468Snon 176367468Snon case 1: 176467468Snon slp->sl_rstep ++; 176567468Snon slp->sl_flags &= ~HW_RESUME; 176667468Snon scsi_low_start(slp); 176767468Snon break; 176867468Snon 176967468Snon case 2: 177067468Snon break; 177167468Snon } 177267468Snon splx(s); 177367468Snon} 177467468Snon 177567468Snonstatic int 177667468Snonscsi_low_init(slp, flags) 177767468Snon struct scsi_low_softc *slp; 177867468Snon u_int flags; 177967468Snon{ 178079697Snon int rv = 0; 178167468Snon 178279697Snon slp->sl_flags |= HW_INITIALIZING; 178379697Snon 178479697Snon /* clear power control timeout */ 178567468Snon if ((slp->sl_flags & HW_POWERCTRL) != 0) 178667468Snon { 178779697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp, 178879697Snon SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP); 178967468Snon slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME); 179067468Snon slp->sl_active = 1; 179167468Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 179267468Snon } 179367468Snon 179467468Snon /* reset current nexus */ 179567468Snon scsi_low_reset_nexus(slp, flags); 179667468Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 179779697Snon { 179879697Snon rv = EBUSY; 179979697Snon goto out; 180079697Snon } 180167468Snon 180279697Snon if (flags != SCSI_LOW_RESTART_SOFT) 180379697Snon { 180479697Snon rv = ((*slp->sl_funcs->scsi_low_init) (slp, flags)); 180579697Snon } 180667468Snon 180779697Snonout: 180879697Snon slp->sl_flags &= ~HW_INITIALIZING; 180979697Snon return rv; 181067468Snon} 181167468Snon 181267468Snon/************************************************************** 181367468Snon * allocate lun_info 181467468Snon **************************************************************/ 181567468Snonstatic struct lun_info * 181667468Snonscsi_low_alloc_li(ti, lun, alloc) 181767468Snon struct targ_info *ti; 181867468Snon int lun; 181967468Snon int alloc; 182067468Snon{ 182179697Snon struct scsi_low_softc *slp = ti->ti_sc; 182267468Snon struct lun_info *li; 182367468Snon 182467468Snon li = LIST_FIRST(&ti->ti_litab); 182567468Snon if (li != NULL) 182667468Snon { 182767468Snon if (li->li_lun == lun) 182867468Snon return li; 182967468Snon 183067468Snon while ((li = LIST_NEXT(li, lun_chain)) != NULL) 183167468Snon { 183267468Snon if (li->li_lun == lun) 183367468Snon { 183467468Snon LIST_REMOVE(li, lun_chain); 183567468Snon LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); 183667468Snon return li; 183767468Snon } 183867468Snon } 183967468Snon } 184067468Snon 184167468Snon if (alloc == 0) 184267468Snon return li; 184367468Snon 184479697Snon li = SCSI_LOW_MALLOC(ti->ti_lunsize); 184567468Snon if (li == NULL) 1846106890Simp panic("no lun info mem"); 184767468Snon 184879697Snon SCSI_LOW_BZERO(li, ti->ti_lunsize); 184967468Snon li->li_lun = lun; 185067468Snon li->li_ti = ti; 185167468Snon 185279697Snon li->li_cfgflags = SCSI_LOW_SYNC | SCSI_LOW_LINK | SCSI_LOW_DISC | 185379697Snon SCSI_LOW_QTAG; 185479697Snon li->li_quirks = li->li_diskflags = SCSI_LOW_DISK_LFLAGS; 185579697Snon li->li_flags_valid = SCSI_LOW_LUN_FLAGS_USER_VALID; 185679697Snon#ifdef SCSI_LOW_FLAGS_QUIRKS_OK 185779697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 185879697Snon#endif /* SCSI_LOW_FLAGS_QUIRKS_OK */ 185979697Snon 186079697Snon li->li_qtagbits = (u_int) -1; 186179697Snon 186279697Snon TAILQ_INIT(&li->li_discq); 186367468Snon LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); 186467468Snon 186579697Snon /* host specific structure initialization per lun */ 186679697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 186779697Snon (*slp->sl_funcs->scsi_low_lun_init) 186879697Snon (slp, ti, li, SCSI_LOW_INFO_ALLOC); 186979697Snon scsi_low_calcf_lun(li); 187067468Snon return li; 187167468Snon} 187267468Snon 187367468Snon/************************************************************** 187467468Snon * allocate targ_info 187567468Snon **************************************************************/ 187667468Snonstatic struct targ_info * 187779697Snonscsi_low_alloc_ti(slp, targ) 187867468Snon struct scsi_low_softc *slp; 187979697Snon int targ; 188067468Snon{ 188167468Snon struct targ_info *ti; 188267468Snon 188371999Sphk if (TAILQ_FIRST(&slp->sl_titab) == NULL) 188467468Snon TAILQ_INIT(&slp->sl_titab); 188567468Snon 188679697Snon ti = SCSI_LOW_MALLOC(slp->sl_targsize); 188767468Snon if (ti == NULL) 1888106890Simp panic("%s short of memory", slp->sl_xname); 188967468Snon 189079697Snon SCSI_LOW_BZERO(ti, slp->sl_targsize); 189167468Snon ti->ti_id = targ; 189267468Snon ti->ti_sc = slp; 189367468Snon 189467468Snon slp->sl_ti[targ] = ti; 189567468Snon TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain); 189667468Snon LIST_INIT(&ti->ti_litab); 189767468Snon 189879697Snon ti->ti_quirks = ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS; 189979697Snon ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8; 190079697Snon ti->ti_flags_valid = SCSI_LOW_TARG_FLAGS_USER_VALID; 190179697Snon#ifdef SCSI_LOW_FLAGS_QUIRKS_OK 190279697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 190379697Snon#endif /* SCSI_LOW_FLAGS_QUIRKS_OK */ 190473025Snon 190579697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 190679697Snon { 190779697Snon (*slp->sl_funcs->scsi_low_targ_init) 190879697Snon (slp, ti, SCSI_LOW_INFO_ALLOC); 190979697Snon } 191079697Snon scsi_low_calcf_target(ti); 191167468Snon return ti; 191267468Snon} 191367468Snon 191467468Snonstatic void 191567468Snonscsi_low_free_ti(slp) 191667468Snon struct scsi_low_softc *slp; 191767468Snon{ 191867468Snon struct targ_info *ti, *tib; 191967468Snon struct lun_info *li, *nli; 192067468Snon 192171999Sphk for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib) 192267468Snon { 192367468Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli) 192467468Snon { 192579697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 192679697Snon { 192779697Snon (*slp->sl_funcs->scsi_low_lun_init) 192879697Snon (slp, ti, li, SCSI_LOW_INFO_DEALLOC); 192979697Snon } 193067468Snon nli = LIST_NEXT(li, lun_chain); 193179697Snon SCSI_LOW_FREE(li); 193267468Snon } 193379697Snon 193479697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 193579697Snon { 193679697Snon (*slp->sl_funcs->scsi_low_targ_init) 193779697Snon (slp, ti, SCSI_LOW_INFO_DEALLOC); 193879697Snon } 193979697Snon tib = TAILQ_NEXT(ti, ti_chain); 194079697Snon SCSI_LOW_FREE(ti); 194167468Snon } 194267468Snon} 194367468Snon 194467468Snon/************************************************************** 194567468Snon * timeout 194667468Snon **************************************************************/ 194767468Snonvoid 194879697Snonscsi_low_bus_idle(slp) 194979697Snon struct scsi_low_softc *slp; 195079697Snon{ 195179697Snon 195279697Snon slp->sl_retry_sel = 0; 195379697Snon if (slp->sl_Tnexus == NULL) 195479697Snon scsi_low_start(slp); 195579697Snon} 195679697Snon 195779697Snonstatic void 195867468Snonscsi_low_timeout(arg) 195967468Snon void *arg; 196067468Snon{ 196167468Snon struct scsi_low_softc *slp = arg; 196279697Snon int s; 196379697Snon 196479697Snon s = SCSI_LOW_SPLSCSI(); 196579697Snon (void) scsi_low_timeout_check(slp); 196679697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 196779697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 196879697Snon splx(s); 196979697Snon} 197079697Snon 197179697Snonstatic int 197279697Snonscsi_low_timeout_check(slp) 197379697Snon struct scsi_low_softc *slp; 197479697Snon{ 197567468Snon struct targ_info *ti; 197679697Snon struct lun_info *li; 197767468Snon struct slccb *cb = NULL; /* XXX */ 197867468Snon 197979697Snon /* selection restart */ 198079697Snon if (slp->sl_retry_sel != 0) 198167468Snon { 198279697Snon slp->sl_retry_sel = 0; 198379697Snon if (slp->sl_Tnexus != NULL) 198479697Snon goto step1; 198567468Snon 198679697Snon cb = TAILQ_FIRST(&slp->sl_start); 198779697Snon if (cb == NULL) 198879697Snon goto step1; 198979697Snon 199079697Snon if (cb->ccb_selrcnt >= SCSI_LOW_MAX_SELECTION_RETRY) 199167468Snon { 199279697Snon cb->ccb_flags |= CCB_NORETRY; 199379697Snon cb->ccb_error |= SELTIMEOUTIO; 199479697Snon if (scsi_low_revoke_ccb(slp, cb, 1) != NULL) 1995106890Simp panic("%s: ccb not finished", slp->sl_xname); 199667468Snon } 199779697Snon 199879697Snon if (slp->sl_Tnexus == NULL) 199979697Snon scsi_low_start(slp); 200067468Snon } 200179697Snon 200279697Snon /* call hardware timeout */ 200379697Snonstep1: 200479697Snon if (slp->sl_funcs->scsi_low_timeout != NULL) 200567468Snon { 200679697Snon (*slp->sl_funcs->scsi_low_timeout) (slp); 200779697Snon } 200879697Snon 200979697Snon if (slp->sl_timeout_count ++ < 201079697Snon SCSI_LOW_TIMEOUT_CHECK_INTERVAL * SCSI_LOW_TIMEOUT_HZ) 201179697Snon return 0; 201279697Snon 201379697Snon slp->sl_timeout_count = 0; 201479697Snon if (slp->sl_nio > 0) 201579697Snon { 201679697Snon if ((cb = slp->sl_Qnexus) != NULL) 201767468Snon { 201867468Snon cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 201967468Snon if (cb->ccb_tc < 0) 202067468Snon goto bus_reset; 202167468Snon } 202279697Snon else if (slp->sl_disc == 0) 202367468Snon { 202479697Snon if ((cb = TAILQ_FIRST(&slp->sl_start)) == NULL) 202579697Snon return 0; 202667468Snon 202779697Snon cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 202879697Snon if (cb->ccb_tc < 0) 202979697Snon goto bus_reset; 203079697Snon } 203179697Snon else for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 203279697Snon ti = TAILQ_NEXT(ti, ti_chain)) 203379697Snon { 203479697Snon if (ti->ti_disc == 0) 203579697Snon continue; 203667468Snon 203779697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 203879697Snon li = LIST_NEXT(li, lun_chain)) 203967468Snon { 204079697Snon for (cb = TAILQ_FIRST(&li->li_discq); 204179697Snon cb != NULL; 204279697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 204379697Snon { 204479697Snon cb->ccb_tc -= 204579697Snon SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 204679697Snon if (cb->ccb_tc < 0) 204779697Snon goto bus_reset; 204879697Snon } 204967468Snon } 205067468Snon } 205179697Snon 205267468Snon } 205379697Snon else if ((slp->sl_flags & HW_POWERCTRL) != 0) 205479697Snon { 205579697Snon if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0) 205679697Snon return 0; 205767468Snon 205879697Snon if (slp->sl_active != 0) 205979697Snon { 206079697Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 206179697Snon slp->sl_active = 0; 206279697Snon return 0; 206379697Snon } 206467468Snon 206579697Snon slp->sl_powc --; 206679697Snon if (slp->sl_powc < 0) 206779697Snon { 206879697Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 206979697Snon slp->sl_flags |= HW_POWDOWN; 207079697Snon (*slp->sl_funcs->scsi_low_power) 207179697Snon (slp, SCSI_LOW_POWDOWN); 207279697Snon } 207379697Snon } 207479697Snon return 0; 207567468Snon 207667468Snonbus_reset: 207767468Snon cb->ccb_error |= TIMEOUTIO; 207879697Snon printf("%s: slccb (0x%lx) timeout!\n", slp->sl_xname, (u_long) cb); 207967468Snon scsi_low_info(slp, NULL, "scsi bus hangup. try to recover."); 208067468Snon scsi_low_init(slp, SCSI_LOW_RESTART_HARD); 208167468Snon scsi_low_start(slp); 208279697Snon return ERESTART; 208367468Snon} 208467468Snon 208567468Snon 208679697Snonstatic int 208779697Snonscsi_low_abort_ccb(slp, cb) 208879697Snon struct scsi_low_softc *slp; 208979697Snon struct slccb *cb; 209079697Snon{ 209179697Snon struct targ_info *ti; 209279697Snon struct lun_info *li; 209379697Snon u_int msg; 209467468Snon 209579697Snon if (cb == NULL) 209679697Snon return EINVAL; 209779697Snon if ((cb->ccb_omsgoutflag & 209879697Snon (SCSI_LOW_MSG_ABORT | SCSI_LOW_MSG_ABORT_QTAG)) != 0) 209979697Snon return EBUSY; 210067468Snon 210179697Snon ti = cb->ti; 210279697Snon li = cb->li; 210379697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 210479697Snon msg = SCSI_LOW_MSG_ABORT; 210579697Snon else 210679697Snon msg = SCSI_LOW_MSG_ABORT_QTAG; 210767468Snon 210879697Snon cb->ccb_error |= ABORTIO; 210979697Snon cb->ccb_flags |= CCB_NORETRY; 211079697Snon scsi_low_ccb_message_assert(cb, msg); 211167468Snon 211279697Snon if (cb == slp->sl_Qnexus) 211379697Snon { 211479697Snon scsi_low_assert_msg(slp, ti, msg, 1); 211579697Snon } 211679697Snon else if ((cb->ccb_flags & CCB_DISCQ) != 0) 211779697Snon { 211879697Snon if (scsi_low_revoke_ccb(slp, cb, 0) == NULL) 2119106890Simp panic("%s: revoked ccb done", slp->sl_xname); 212067468Snon 212179697Snon cb->ccb_flags |= CCB_STARTQ; 212279697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 212367468Snon 212479697Snon if (slp->sl_Tnexus == NULL) 212579697Snon scsi_low_start(slp); 212679697Snon } 212779697Snon else 212879697Snon { 212979697Snon if (scsi_low_revoke_ccb(slp, cb, 1) != NULL) 2130106890Simp panic("%s: revoked ccb retried", slp->sl_xname); 213179697Snon } 213279697Snon return 0; 213367468Snon} 213467468Snon 213579697Snon/************************************************************** 213679697Snon * Generic SCSI INTERFACE 213779697Snon **************************************************************/ 213867468Snonint 213979697Snonscsi_low_attach(slp, openings, ntargs, nluns, targsize, lunsize) 214067468Snon struct scsi_low_softc *slp; 214179697Snon int openings, ntargs, nluns, targsize, lunsize; 214267468Snon{ 214367468Snon struct targ_info *ti; 214467468Snon struct lun_info *li; 214579697Snon int s, i, nccb, rv; 214667468Snon 214779697Snon#ifdef SCSI_LOW_INTERFACE_XS 214879697Snon slp->sl_osdep_fp = &scsi_low_osdep_funcs_xs; 214979697Snon#endif /* SCSI_LOW_INTERFACE_XS */ 215079697Snon#ifdef SCSI_LOW_INTERFACE_CAM 215179697Snon slp->sl_osdep_fp = &scsi_low_osdep_funcs_cam; 215279697Snon#endif /* SCSI_LOW_INTERFACE_CAM */ 215379697Snon 215479697Snon if (slp->sl_osdep_fp == NULL) 2155106890Simp panic("scsi_low: interface not spcified"); 215679697Snon 215767468Snon if (ntargs > SCSI_LOW_NTARGETS) 215867468Snon { 215967468Snon printf("scsi_low: %d targets are too large\n", ntargs); 216067468Snon printf("change kernel options SCSI_LOW_NTARGETS"); 216179697Snon return EINVAL; 216267468Snon } 216367468Snon 216479697Snon if (openings <= 0) 216579697Snon slp->sl_openings = (SCSI_LOW_NCCB / ntargs); 216679697Snon else 216779697Snon slp->sl_openings = openings; 216879697Snon slp->sl_ntargs = ntargs; 216979697Snon slp->sl_nluns = nluns; 217079697Snon slp->sl_max_retry = SCSI_LOW_MAX_RETRY; 217167468Snon 217279697Snon if (lunsize < sizeof(struct lun_info)) 217379697Snon lunsize = sizeof(struct lun_info); 217479697Snon 217579697Snon if (targsize < sizeof(struct targ_info)) 217679697Snon targsize = sizeof(struct targ_info); 217779697Snon 217879697Snon slp->sl_targsize = targsize; 217967468Snon for (i = 0; i < ntargs; i ++) 218067468Snon { 218179697Snon ti = scsi_low_alloc_ti(slp, i); 218279697Snon ti->ti_lunsize = lunsize; 218367468Snon li = scsi_low_alloc_li(ti, 0, 1); 218467468Snon } 218567468Snon 218667468Snon /* initialize queue */ 218779697Snon nccb = openings * ntargs; 218867468Snon if (nccb >= SCSI_LOW_NCCB || nccb <= 0) 218967468Snon nccb = SCSI_LOW_NCCB; 219067468Snon scsi_low_init_ccbque(nccb); 219167468Snon TAILQ_INIT(&slp->sl_start); 219267468Snon 219379697Snon /* call os depend attach */ 219479697Snon s = SCSI_LOW_SPLSCSI(); 219579697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_attach) (slp); 219679697Snon if (rv != 0) 219779697Snon { 219879697Snon splx(s); 219979697Snon printf("%s: scsi_low_attach: osdep attach failed\n", 220079697Snon slp->sl_xname); 220179697Snon return EINVAL; 220279697Snon } 220367468Snon 220479697Snon /* check hardware */ 220579697Snon SCSI_LOW_DELAY(1000); /* wait for 1ms */ 220679697Snon if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0) 220779697Snon { 220879697Snon splx(s); 220979697Snon printf("%s: scsi_low_attach: initialization failed\n", 221079697Snon slp->sl_xname); 221179697Snon return EINVAL; 221279697Snon } 221367468Snon 221467468Snon /* start watch dog */ 221579697Snon slp->sl_timeout_count = 0; 221679697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 221779697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 221879697Snon LIST_INSERT_HEAD(&sl_tab, slp, sl_chain); 221967468Snon 222079697Snon /* fake call */ 222179697Snon scsi_low_abort_ccb(slp, scsi_low_find_ccb(slp, 0, 0, NULL)); 222267468Snon 222379697Snon#ifdef SCSI_LOW_START_UP_CHECK 222479697Snon /* probing devices */ 222579697Snon scsi_low_start_up(slp); 222679697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 222767468Snon 222879697Snon /* call os depend attach done*/ 222979697Snon (*slp->sl_osdep_fp->scsi_low_osdep_world_start) (slp); 223079697Snon splx(s); 223179697Snon return 0; 223267468Snon} 223367468Snon 223467468Snonint 223567468Snonscsi_low_dettach(slp) 223667468Snon struct scsi_low_softc *slp; 223767468Snon{ 223879697Snon int s, rv; 223967468Snon 224079697Snon s = SCSI_LOW_SPLSCSI(); 224179697Snon if (scsi_low_is_busy(slp) != 0) 224279697Snon { 224379697Snon splx(s); 224467468Snon return EBUSY; 224579697Snon } 224667468Snon 224779697Snon scsi_low_deactivate(slp); 224867468Snon 224979697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_dettach) (slp); 225079697Snon if (rv != 0) 225179697Snon { 225279697Snon splx(s); 225379697Snon return EBUSY; 225479697Snon } 225567468Snon 225667468Snon scsi_low_free_ti(slp); 225779697Snon LIST_REMOVE(slp, sl_chain); 225879697Snon splx(s); 225967468Snon return 0; 226067468Snon} 226167468Snon 226279697Snon/************************************************************** 226379697Snon * Generic enqueue 226479697Snon **************************************************************/ 226579697Snonstatic int 226679697Snonscsi_low_enqueue(slp, ti, li, cb, flags, msg) 226779697Snon struct scsi_low_softc *slp; 226867468Snon struct targ_info *ti; 226967468Snon struct lun_info *li; 227067468Snon struct slccb *cb; 227179697Snon u_int flags, msg; 227279697Snon{ 227367468Snon 227479697Snon cb->ti = ti; 227579697Snon cb->li = li; 227667468Snon 227779697Snon scsi_low_ccb_message_assert(cb, msg); 227867468Snon 227979697Snon cb->ccb_otag = cb->ccb_tag = SCSI_LOW_UNKTAG; 228079697Snon scsi_low_alloc_qtag(cb); 228167468Snon 228279697Snon cb->ccb_flags = flags | CCB_STARTQ; 228379697Snon cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 228479697Snon cb->ccb_error |= PENDINGIO; 228579697Snon 228679697Snon if ((flags & CCB_URGENT) != 0) 228779697Snon { 228879697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 228979697Snon } 229079697Snon else 229179697Snon { 229267468Snon TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain); 229379697Snon } 229467468Snon 229579697Snon slp->sl_nio ++; 229667468Snon 229779697Snon if (slp->sl_Tnexus == NULL) 229879697Snon scsi_low_start(slp); 229979697Snon return 0; 230079697Snon} 230167468Snon 230279697Snonstatic int 230379697Snonscsi_low_message_enqueue(slp, ti, li, flags) 230479697Snon struct scsi_low_softc *slp; 230579697Snon struct targ_info *ti; 230679697Snon struct lun_info *li; 230779697Snon u_int flags; 230879697Snon{ 230979697Snon struct slccb *cb; 231079697Snon u_int tmsgflags; 231167468Snon 231279697Snon tmsgflags = ti->ti_setup_msg; 231379697Snon ti->ti_setup_msg = 0; 231467468Snon 231579697Snon flags |= CCB_NORETRY; 231679697Snon if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL) 231779697Snon return ENOMEM; 231867468Snon 231979697Snon cb->osdep = NULL; 232079697Snon cb->bp = NULL; 232179697Snon scsi_low_enqueue(slp, ti, li, cb, flags, tmsgflags); 232279697Snon return 0; 232379697Snon} 232467468Snon 232579697Snon/************************************************************** 232679697Snon * Generic Start & Done 232779697Snon **************************************************************/ 232879697Snon#define SLSC_MODE_SENSE_SHORT 0x1a 232979697Snonstatic u_int8_t ss_cmd[6] = {START_STOP, 0, 0, 0, SSS_START, 0}; 233079697Snonstatic u_int8_t sms_cmd[6] = {SLSC_MODE_SENSE_SHORT, 0x08, 0x0a, 0, 233179697Snon sizeof(struct scsi_low_mode_sense_data), 0}; 233279697Snonstatic u_int8_t inq_cmd[6] = {INQUIRY, 0, 0, 0, 233379697Snon sizeof(struct scsi_low_inq_data), 0}; 233479697Snonstatic u_int8_t unit_ready_cmd[6]; 233592770Salfredstatic int scsi_low_setup_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *); 233692770Salfredstatic int scsi_low_sense_abort_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *); 233792770Salfredstatic int scsi_low_resume(struct scsi_low_softc *); 233879697Snon 233979697Snonstatic void 234079697Snonscsi_low_unit_ready_cmd(cb) 234179697Snon struct slccb *cb; 234279697Snon{ 234379697Snon 234479697Snon cb->ccb_scp.scp_cmd = unit_ready_cmd; 234579697Snon cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd); 234679697Snon cb->ccb_scp.scp_datalen = 0; 234779697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 234879697Snon cb->ccb_tcmax = 15; 234967468Snon} 235079697Snon 235167468Snonstatic int 235279697Snonscsi_low_sense_abort_start(slp, ti, li, cb) 235379697Snon struct scsi_low_softc *slp; 235467468Snon struct targ_info *ti; 235579697Snon struct lun_info *li; 235667468Snon struct slccb *cb; 235779697Snon{ 235867468Snon 235979697Snon cb->ccb_scp.scp_cmdlen = 6; 236079697Snon SCSI_LOW_BZERO(cb->ccb_scsi_cmd, cb->ccb_scp.scp_cmdlen); 236179697Snon cb->ccb_scsi_cmd[0] = REQUEST_SENSE; 236279697Snon cb->ccb_scsi_cmd[4] = sizeof(cb->ccb_sense); 236379697Snon cb->ccb_scp.scp_cmd = cb->ccb_scsi_cmd; 236479697Snon cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense; 236579697Snon cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense); 236679697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 236779697Snon cb->ccb_tcmax = 15; 236879697Snon scsi_low_ccb_message_clear(cb); 236979697Snon if ((cb->ccb_flags & CCB_CLEARQ) != 0) 237067468Snon { 237179697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 237267468Snon } 237379697Snon else 237479697Snon { 237579697Snon SCSI_LOW_BZERO(&cb->ccb_sense, sizeof(cb->ccb_sense)); 237679697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 237779697Snon scsi_low_assert_msg(slp, ti, ti->ti_setup_msg_done, 0); 237879697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 237979697Snon } 238067468Snon 238179697Snon return SCSI_LOW_START_NO_QTAG; 238279697Snon} 238367468Snon 238479697Snonstatic int 238579697Snonscsi_low_setup_start(slp, ti, li, cb) 238679697Snon struct scsi_low_softc *slp; 238779697Snon struct targ_info *ti; 238879697Snon struct lun_info *li; 238979697Snon struct slccb *cb; 239079697Snon{ 239167468Snon 239279697Snon switch(li->li_state) 239379697Snon { 239479697Snon case SCSI_LOW_LUN_SLEEP: 239579697Snon scsi_low_unit_ready_cmd(cb); 239679697Snon break; 239767468Snon 239879697Snon case SCSI_LOW_LUN_START: 239979697Snon cb->ccb_scp.scp_cmd = ss_cmd; 240079697Snon cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd); 240179697Snon cb->ccb_scp.scp_datalen = 0; 240279697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 240379697Snon cb->ccb_tcmax = 30; 240479697Snon break; 240567468Snon 240679697Snon case SCSI_LOW_LUN_INQ: 240779697Snon cb->ccb_scp.scp_cmd = inq_cmd; 240879697Snon cb->ccb_scp.scp_cmdlen = sizeof(inq_cmd); 240979697Snon cb->ccb_scp.scp_data = (u_int8_t *)&li->li_inq; 241079697Snon cb->ccb_scp.scp_datalen = sizeof(li->li_inq); 241179697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 241279697Snon cb->ccb_tcmax = 15; 241379697Snon break; 241467468Snon 241579697Snon case SCSI_LOW_LUN_MODEQ: 241679697Snon cb->ccb_scp.scp_cmd = sms_cmd; 241779697Snon cb->ccb_scp.scp_cmdlen = sizeof(sms_cmd); 241879697Snon cb->ccb_scp.scp_data = (u_int8_t *)&li->li_sms; 241979697Snon cb->ccb_scp.scp_datalen = sizeof(li->li_sms); 242079697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 242179697Snon cb->ccb_tcmax = 15; 242279697Snon return SCSI_LOW_START_QTAG; 242367468Snon 242479697Snon default: 2425106890Simp panic("%s: no setup phase", slp->sl_xname); 242667468Snon } 242767468Snon 242879697Snon return SCSI_LOW_START_NO_QTAG; 242967468Snon} 243067468Snon 243179697Snonstatic int 243279697Snonscsi_low_resume(slp) 243379697Snon struct scsi_low_softc *slp; 243467468Snon{ 243567468Snon 243679697Snon if (slp->sl_flags & HW_RESUME) 243779697Snon return EJUSTRETURN; 243879697Snon slp->sl_flags &= ~HW_POWDOWN; 243979697Snon if (slp->sl_funcs->scsi_low_power != NULL) 244079697Snon { 244179697Snon slp->sl_flags |= HW_RESUME; 244279697Snon slp->sl_rstep = 0; 244379697Snon (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); 244479697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 244579697Snon (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, 244679697Snon SCSI_LOW_TIMEOUT_START); 244779697Snon return EJUSTRETURN; 244879697Snon } 244979697Snon return 0; 245067468Snon} 245167468Snon 245267468Snonstatic void 245367468Snonscsi_low_start(slp) 245467468Snon struct scsi_low_softc *slp; 245567468Snon{ 245667468Snon struct targ_info *ti; 245767468Snon struct lun_info *li; 245867468Snon struct slccb *cb; 245967468Snon int rv; 246067468Snon 246179697Snon /* check hardware exists or under initializations ? */ 246279697Snon if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0) 246367468Snon return; 246467468Snon 246567468Snon /* check hardware power up ? */ 246667468Snon if ((slp->sl_flags & HW_POWERCTRL) != 0) 246767468Snon { 246867468Snon slp->sl_active ++; 246967468Snon if (slp->sl_flags & (HW_POWDOWN | HW_RESUME)) 247067468Snon { 247179697Snon if (scsi_low_resume(slp) == EJUSTRETURN) 247267468Snon return; 247367468Snon } 247467468Snon } 247567468Snon 247667468Snon /* setup nexus */ 247767468Snon#ifdef SCSI_LOW_DIAGNOSTIC 247879697Snon if (slp->sl_Tnexus || slp->sl_Lnexus || slp->sl_Qnexus) 247967468Snon { 248067468Snon scsi_low_info(slp, NULL, "NEXUS INCOSISTENT"); 2481106890Simp panic("%s: inconsistent", slp->sl_xname); 248267468Snon } 248367468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 248467468Snon 248579697Snon for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL; 248679697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 248767468Snon { 248867468Snon li = cb->li; 248979697Snon 249079697Snon if (li->li_disc == 0) 249179697Snon { 249267468Snon goto scsi_low_cmd_start; 249379697Snon } 249479697Snon else if (li->li_nqio > 0) 249579697Snon { 249679697Snon if (li->li_nqio < li->li_maxnqio || 249779697Snon (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 249879697Snon goto scsi_low_cmd_start; 249979697Snon } 250067468Snon } 250167468Snon return; 250267468Snon 250367468Snonscsi_low_cmd_start: 250479697Snon cb->ccb_flags &= ~CCB_STARTQ; 250579697Snon TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); 250679697Snon ti = cb->ti; 250767468Snon 250867468Snon /* clear all error flag bits (for restart) */ 250967468Snon cb->ccb_error = 0; 251079697Snon cb->ccb_datalen = -1; 251179697Snon cb->ccb_scp.scp_status = ST_UNKNOWN; 251267468Snon 251367468Snon /* setup nexus pointer */ 251479697Snon slp->sl_Qnexus = cb; 251579697Snon slp->sl_Lnexus = li; 251679697Snon slp->sl_Tnexus = ti; 251767468Snon 251867468Snon /* initialize msgsys */ 251967468Snon scsi_low_init_msgsys(slp, ti); 252067468Snon 252179697Snon /* exec cmd */ 252279697Snon if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 252367468Snon { 252479697Snon /* CA state or forced abort */ 252579697Snon rv = scsi_low_sense_abort_start(slp, ti, li, cb); 252667468Snon } 252779697Snon else if (li->li_state >= SCSI_LOW_LUN_OK) 252867468Snon { 252979697Snon cb->ccb_flags &= ~CCB_INTERNAL; 253079697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, cb); 253179697Snon if (cb->ccb_msgoutflag != 0) 253279697Snon { 253379697Snon scsi_low_ccb_message_exec(slp, cb); 253479697Snon } 253567468Snon } 253679697Snon else 253767468Snon { 253879697Snon cb->ccb_flags |= CCB_INTERNAL; 253979697Snon rv = scsi_low_setup_start(slp, ti, li, cb); 254079697Snon } 254167468Snon 254279697Snon /* allocate qtag */ 254379697Snon#define SCSI_LOW_QTAG_OK (SCSI_LOW_QTAG | SCSI_LOW_DISC) 254467468Snon 254579697Snon if (rv == SCSI_LOW_START_QTAG && 254679697Snon (li->li_flags & SCSI_LOW_QTAG_OK) == SCSI_LOW_QTAG_OK && 254779697Snon li->li_maxnqio > 0) 254879697Snon { 254979697Snon u_int qmsg; 255067468Snon 255179697Snon scsi_low_activate_qtag(cb); 255279697Snon if ((scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 255379697Snon SCSI_LOW_CMD_ORDERED_QTAG) != 0) 255479697Snon qmsg = SCSI_LOW_MSG_ORDERED_QTAG; 255579697Snon else if ((cb->ccb_flags & CCB_URGENT) != 0) 255679697Snon qmsg = SCSI_LOW_MSG_HEAD_QTAG; 255779697Snon else 255879697Snon qmsg = SCSI_LOW_MSG_SIMPLE_QTAG; 255979697Snon scsi_low_assert_msg(slp, ti, qmsg, 0); 256067468Snon } 256167468Snon 256267468Snon /* timeout */ 256367468Snon if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT) 256467468Snon cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 256567468Snon cb->ccb_tc = cb->ccb_tcmax; 256667468Snon 256767468Snon /* setup saved scsi data pointer */ 256867468Snon cb->ccb_sscp = cb->ccb_scp; 256967468Snon 257067468Snon /* setup current scsi pointer */ 257167468Snon slp->sl_scp = cb->ccb_sscp; 257267468Snon slp->sl_error = cb->ccb_error; 257367468Snon 257479697Snon /* assert always an identify msg */ 257579697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); 257679697Snon 257779697Snon /* debug section */ 257879697Snon#ifdef SCSI_LOW_DIAGNOSTIC 257979697Snon scsi_low_msg_log_init(&ti->ti_log_msgin); 258079697Snon scsi_low_msg_log_init(&ti->ti_log_msgout); 258179697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 258279697Snon 258367468Snon /* selection start */ 258479697Snon slp->sl_selid = cb; 258567468Snon rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb)); 258667468Snon if (rv == SCSI_LOW_START_OK) 258767468Snon { 258867468Snon#ifdef SCSI_LOW_STATICS 258967468Snon scsi_low_statics.nexus_win ++; 259067468Snon#endif /* SCSI_LOW_STATICS */ 259167468Snon return; 259267468Snon } 259367468Snon 259479697Snon scsi_low_arbit_fail(slp, cb); 259567468Snon#ifdef SCSI_LOW_STATICS 259667468Snon scsi_low_statics.nexus_fail ++; 259767468Snon#endif /* SCSI_LOW_STATICS */ 259867468Snon} 259967468Snon 260067468Snonvoid 260179697Snonscsi_low_arbit_fail(slp, cb) 260267468Snon struct scsi_low_softc *slp; 260379697Snon struct slccb *cb; 260479697Snon{ 260579697Snon struct targ_info *ti = cb->ti; 260679697Snon 260779697Snon scsi_low_deactivate_qtag(cb); 260879697Snon scsi_low_ccb_message_retry(cb); 260979697Snon cb->ccb_flags |= CCB_STARTQ; 261079697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 261179697Snon 261279697Snon scsi_low_bus_release(slp, ti); 261379697Snon 261479697Snon cb->ccb_selrcnt ++; 261579697Snon if (slp->sl_disc == 0) 261679697Snon { 261779697Snon#ifdef SCSI_LOW_DIAGNOSTIC 261879697Snon printf("%s: try selection again\n", slp->sl_xname); 261979697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 262079697Snon slp->sl_retry_sel = 1; 262179697Snon } 262279697Snon} 262379697Snon 262479697Snonstatic void 262579697Snonscsi_low_bus_release(slp, ti) 262679697Snon struct scsi_low_softc *slp; 262767468Snon struct targ_info *ti; 262867468Snon{ 262967468Snon 263079697Snon if (ti->ti_disc > 0) 263179697Snon { 263279697Snon SCSI_LOW_SETUP_PHASE(ti, PH_DISC); 263379697Snon } 263479697Snon else 263579697Snon { 263679697Snon SCSI_LOW_SETUP_PHASE(ti, PH_NULL); 263779697Snon } 263879697Snon 263967468Snon /* clear all nexus pointer */ 264079697Snon slp->sl_Qnexus = NULL; 264179697Snon slp->sl_Lnexus = NULL; 264279697Snon slp->sl_Tnexus = NULL; 264367468Snon 264467468Snon /* clear selection assert */ 264567468Snon slp->sl_selid = NULL; 264667468Snon 264767468Snon /* clear nexus data */ 264867468Snon slp->sl_scp.scp_direction = SCSI_LOW_RWUNK; 264979697Snon 265079697Snon /* clear phase change counter */ 265179697Snon slp->sl_ph_count = 0; 265267468Snon} 265367468Snon 265467468Snonstatic int 265579697Snonscsi_low_setup_done(slp, cb) 265667468Snon struct scsi_low_softc *slp; 265767468Snon struct slccb *cb; 265867468Snon{ 265967468Snon struct targ_info *ti; 266067468Snon struct lun_info *li; 266167468Snon 266267468Snon ti = cb->ti; 266367468Snon li = cb->li; 266479697Snon 266579697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 266667468Snon { 266779697Snon cb->ccb_error |= ABORTIO; 266879697Snon return SCSI_LOW_DONE_COMPLETE; 266979697Snon } 267079697Snon 267179697Snon /* XXX: special huck for selection timeout */ 267279697Snon if (li->li_state == SCSI_LOW_LUN_SLEEP && 267379697Snon (cb->ccb_error & SELTIMEOUTIO) != 0) 267479697Snon { 267579697Snon cb->ccb_error |= ABORTIO; 267679697Snon return SCSI_LOW_DONE_COMPLETE; 267779697Snon } 267879697Snon 267979697Snon switch(li->li_state) 268079697Snon { 268179697Snon case SCSI_LOW_LUN_INQ: 268279697Snon if (cb->ccb_error != 0) 268367468Snon { 268479697Snon li->li_diskflags &= 268579697Snon ~(SCSI_LOW_DISK_LINK | SCSI_LOW_DISK_QTAG); 268679697Snon if (li->li_lun > 0) 268779697Snon goto resume; 268879697Snon ti->ti_diskflags &= 268979697Snon ~(SCSI_LOW_DISK_SYNC | SCSI_LOW_DISK_WIDE); 269067468Snon } 269179697Snon else if ((li->li_inq.sd_version & 7) >= 2 || 269279697Snon (li->li_inq.sd_len >= 4)) 269367468Snon { 269479697Snon if ((li->li_inq.sd_support & 0x2) == 0) 269579697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 269679697Snon if ((li->li_inq.sd_support & 0x8) == 0) 269779697Snon li->li_diskflags &= ~SCSI_LOW_DISK_LINK; 269879697Snon if (li->li_lun > 0) 269979697Snon goto resume; 270079697Snon if ((li->li_inq.sd_support & 0x10) == 0) 270179697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_SYNC; 270279697Snon if ((li->li_inq.sd_support & 0x20) == 0) 270379697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_16; 270479697Snon if ((li->li_inq.sd_support & 0x40) == 0) 270579697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_32; 270679697Snon } 270779697Snon else 270879697Snon { 270979697Snon li->li_diskflags &= 271079697Snon ~(SCSI_LOW_DISK_QTAG | SCSI_LOW_DISK_LINK); 271179697Snon if (li->li_lun > 0) 271279697Snon goto resume; 271379697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE; 271479697Snon } 271579697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_DISK_VALID; 271679697Snonresume: 271779697Snon scsi_low_calcf_target(ti); 271879697Snon scsi_low_calcf_lun(li); 271979697Snon break; 272079697Snon 272179697Snon case SCSI_LOW_LUN_MODEQ: 272279697Snon if (cb->ccb_error != 0) 272379697Snon { 272479697Snon if (cb->ccb_error & SENSEIO) 272567468Snon { 272679697Snon#ifdef SCSI_LOW_DEBUG 272779697Snon if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE) 272879697Snon { 272979697Snon printf("SENSE: [%x][%x][%x][%x][%x]\n", 273079697Snon (u_int) cb->ccb_sense.error_code, 273179697Snon (u_int) cb->ccb_sense.segment, 273279697Snon (u_int) cb->ccb_sense.flags, 273379697Snon (u_int) cb->ccb_sense.add_sense_code, 273479697Snon (u_int) cb->ccb_sense.add_sense_code_qual); 273579697Snon } 273679697Snon#endif /* SCSI_LOW_DEBUG */ 273767468Snon } 273879697Snon else 273979697Snon { 274079697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 274179697Snon } 274279697Snon } 274379697Snon else if ((li->li_sms.sms_cmp.cmp_page & 0x3f) == 0x0a) 274479697Snon { 274579697Snon if (li->li_sms.sms_cmp.cmp_qc & 0x02) 274679697Snon li->li_qflags |= SCSI_LOW_QFLAG_CA_QCLEAR; 274779697Snon else 274879697Snon li->li_qflags &= ~SCSI_LOW_QFLAG_CA_QCLEAR; 274979697Snon if ((li->li_sms.sms_cmp.cmp_qc & 0x01) != 0) 275079697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 275179697Snon } 275279697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_DISK_VALID; 275379697Snon scsi_low_calcf_lun(li); 275479697Snon break; 275567468Snon 275679697Snon default: 275779697Snon break; 275879697Snon } 275979697Snon 276079697Snon li->li_state ++; 276179697Snon if (li->li_state == SCSI_LOW_LUN_OK) 276279697Snon { 276379697Snon scsi_low_calcf_target(ti); 276479697Snon scsi_low_calcf_lun(li); 276579697Snon if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID && 276679697Snon (slp->sl_show_result & SHOW_CALCF_RES) != 0) 276779697Snon { 276879697Snon scsi_low_calcf_show(li); 276979697Snon } 277079697Snon } 277179697Snon 277279697Snon cb->ccb_rcnt --; 277379697Snon return SCSI_LOW_DONE_RETRY; 277479697Snon} 277579697Snon 277679697Snonstatic int 277779697Snonscsi_low_done(slp, cb) 277879697Snon struct scsi_low_softc *slp; 277979697Snon struct slccb *cb; 278079697Snon{ 278179697Snon int rv; 278279697Snon 278379697Snon if (cb->ccb_error == 0) 278479697Snon { 278579697Snon if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 278679697Snon { 278779697Snon#ifdef SCSI_LOW_QCLEAR_AFTER_CA 278879697Snon /* XXX: 278979697Snon * SCSI-2 draft suggests 279079697Snon * page 0x0a QErr bit determins if 279179697Snon * the target aborts or continues 279279697Snon * the queueing io's after CA state resolved. 279379697Snon * However many targets seem not to support 279479697Snon * the page 0x0a. Thus we should manually clear the 279579697Snon * queuing io's after CA state. 279679697Snon */ 279779697Snon if ((cb->ccb_flags & CCB_CLEARQ) == 0) 279867468Snon { 279979697Snon cb->ccb_rcnt --; 280079697Snon cb->ccb_flags |= CCB_CLEARQ; 280179697Snon goto retry; 280279697Snon } 280379697Snon#endif /* SCSI_LOW_QCLEAR_AFTER_CA */ 280479697Snon 280579697Snon if ((cb->ccb_flags & CCB_SENSE) != 0) 280679697Snon cb->ccb_error |= (SENSEIO | ABORTIO); 280779697Snon cb->ccb_flags &= ~(CCB_SENSE | CCB_CLEARQ); 280879697Snon } 280979697Snon else switch (cb->ccb_sscp.scp_status) 281079697Snon { 281179697Snon case ST_GOOD: 281279697Snon case ST_MET: 281379697Snon case ST_INTERGOOD: 281479697Snon case ST_INTERMET: 281579697Snon if (cb->ccb_datalen == 0 || 281679697Snon cb->ccb_scp.scp_datalen == 0) 281767468Snon break; 281867468Snon 281979697Snon if (cb->ccb_scp.scp_cmdlen > 0 && 282079697Snon (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 282179697Snon SCSI_LOW_CMD_RESIDUAL_CHK) == 0) 282279697Snon break; 282379697Snon 282467468Snon cb->ccb_error |= PDMAERR; 282567468Snon break; 282667468Snon 282779697Snon case ST_BUSY: 282879697Snon case ST_QUEFULL: 282979697Snon cb->ccb_error |= (BUSYERR | STATERR); 283079697Snon break; 283179697Snon 283279697Snon case ST_CONFLICT: 283379697Snon cb->ccb_error |= (STATERR | ABORTIO); 283479697Snon break; 283579697Snon 283667468Snon case ST_CHKCOND: 283779697Snon case ST_CMDTERM: 283879697Snon if (cb->ccb_flags & (CCB_AUTOSENSE | CCB_INTERNAL)) 283979697Snon { 284079697Snon cb->ccb_rcnt --; 284173025Snon cb->ccb_flags |= CCB_SENSE; 284273025Snon goto retry; 284373025Snon } 284479697Snon cb->ccb_error |= (UACAERR | STATERR | ABORTIO); 284573025Snon break; 284667468Snon 284779697Snon case ST_UNKNOWN: 284867468Snon default: 284967468Snon cb->ccb_error |= FATALIO; 285067468Snon break; 285167468Snon } 285267468Snon } 285367468Snon else 285467468Snon { 285579697Snon if (cb->ccb_flags & CCB_SENSE) 285667468Snon { 285779697Snon cb->ccb_error |= (SENSEERR | ABORTIO); 285867468Snon } 285979697Snon cb->ccb_flags &= ~(CCB_CLEARQ | CCB_SENSE); 286079697Snon } 286167468Snon 286279697Snon /* internal ccb */ 286379697Snon if ((cb->ccb_flags & CCB_INTERNAL) != 0) 286479697Snon { 286579697Snon if (scsi_low_setup_done(slp, cb) == SCSI_LOW_DONE_RETRY) 286679697Snon goto retry; 286767468Snon } 286867468Snon 286979697Snon /* check a ccb msgout flag */ 287079697Snon if (cb->ccb_omsgoutflag != 0) 287167468Snon { 287279697Snon#define SCSI_LOW_MSG_ABORT_OK (SCSI_LOW_MSG_ABORT | \ 287379697Snon SCSI_LOW_MSG_ABORT_QTAG | \ 287479697Snon SCSI_LOW_MSG_CLEAR_QTAG | \ 287579697Snon SCSI_LOW_MSG_TERMIO) 287679697Snon 287779697Snon if ((cb->ccb_omsgoutflag & SCSI_LOW_MSG_ABORT_OK) != 0) 287867468Snon { 287979697Snon cb->ccb_error |= ABORTIO; 288067468Snon } 288167468Snon } 288267468Snon 288379697Snon /* call OS depend done */ 288479697Snon if (cb->osdep != NULL) 288567468Snon { 288679697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_done) (slp, cb); 288779697Snon if (rv == EJUSTRETURN) 288879697Snon goto retry; 288967468Snon } 289079697Snon else if (cb->ccb_error != 0) 289167468Snon { 289279697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 289379697Snon cb->ccb_error |= ABORTIO; 289479697Snon 289579697Snon if ((cb->ccb_flags & CCB_NORETRY) == 0 && 289679697Snon (cb->ccb_error & ABORTIO) == 0) 289767468Snon goto retry; 289867468Snon } 289979697Snon 290079697Snon /* free our target */ 290179697Snon#ifdef SCSI_LOW_DEBUG 290279697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0) 290367468Snon { 290479697Snon printf(">> SCSI_LOW_DONE_COMPLETE ===============\n"); 290579697Snon scsi_low_print(slp, NULL); 290667468Snon } 290779697Snon#endif /* SCSI_LOW_DEBUG */ 290867468Snon 290979697Snon scsi_low_deactivate_qtag(cb); 291079697Snon scsi_low_dealloc_qtag(cb); 291167468Snon scsi_low_free_ccb(cb); 291279697Snon slp->sl_nio --; 291367468Snon return SCSI_LOW_DONE_COMPLETE; 291467468Snon 291567468Snonretry: 291679697Snon#ifdef SCSI_LOW_DEBUG 291779697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0) 291867468Snon { 291979697Snon printf("** SCSI_LOW_DONE_RETRY ===============\n"); 292079697Snon scsi_low_print(slp, NULL); 292167468Snon } 292279697Snon#endif /* SCSI_LOW_DEBUG */ 292379697Snon 292479697Snon cb->ccb_rcnt ++; 292579697Snon scsi_low_deactivate_qtag(cb); 292679697Snon scsi_low_ccb_message_retry(cb); 292767468Snon return SCSI_LOW_DONE_RETRY; 292867468Snon} 292967468Snon 293067468Snon/************************************************************** 293167468Snon * Reset 293267468Snon **************************************************************/ 293367468Snonstatic void 293479697Snonscsi_low_reset_nexus_target(slp, ti, fdone) 293579697Snon struct scsi_low_softc *slp; 293679697Snon struct targ_info *ti; 293779697Snon int fdone; 293867468Snon{ 293979697Snon struct lun_info *li; 294067468Snon 294179697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 294279697Snon li = LIST_NEXT(li, lun_chain)) 294379697Snon { 294479697Snon scsi_low_reset_nexus_lun(slp, li, fdone); 294579697Snon li->li_state = SCSI_LOW_LUN_SLEEP; 294679697Snon li->li_maxnqio = 0; 294779697Snon } 294879697Snon 294979697Snon ti->ti_disc = 0; 295079697Snon ti->ti_setup_msg = 0; 295179697Snon ti->ti_setup_msg_done = 0; 295279697Snon 295379697Snon ti->ti_osynch.offset = ti->ti_osynch.period = 0; 295479697Snon ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8; 295579697Snon 295679697Snon ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS; 295779697Snon ti->ti_flags_valid &= ~SCSI_LOW_TARG_FLAGS_DISK_VALID; 295879697Snon 295979697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 296079697Snon { 296179697Snon ((*slp->sl_funcs->scsi_low_targ_init) 296279697Snon (slp, ti, SCSI_LOW_INFO_REVOKE)); 296379697Snon } 296479697Snon scsi_low_calcf_target(ti); 296579697Snon 296679697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 296779697Snon li = LIST_NEXT(li, lun_chain)) 296879697Snon { 296979697Snon li->li_flags = 0; 297079697Snon 297179697Snon li->li_diskflags = SCSI_LOW_DISK_LFLAGS; 297279697Snon li->li_flags_valid &= ~SCSI_LOW_LUN_FLAGS_DISK_VALID; 297379697Snon 297479697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 297579697Snon { 297679697Snon ((*slp->sl_funcs->scsi_low_lun_init) 297779697Snon (slp, ti, li, SCSI_LOW_INFO_REVOKE)); 297879697Snon } 297979697Snon scsi_low_calcf_lun(li); 298079697Snon } 298167468Snon} 298267468Snon 298367468Snonstatic void 298467468Snonscsi_low_reset_nexus(slp, fdone) 298567468Snon struct scsi_low_softc *slp; 298667468Snon int fdone; 298767468Snon{ 298867468Snon struct targ_info *ti; 298979697Snon struct slccb *cb, *topcb; 299067468Snon 299179697Snon if ((cb = slp->sl_Qnexus) != NULL) 299267468Snon { 299379697Snon topcb = scsi_low_revoke_ccb(slp, cb, fdone); 299467468Snon } 299579697Snon else 299679697Snon { 299779697Snon topcb = NULL; 299879697Snon } 299967468Snon 300079697Snon for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 300179697Snon ti = TAILQ_NEXT(ti, ti_chain)) 300267468Snon { 300379697Snon scsi_low_reset_nexus_target(slp, ti, fdone); 300479697Snon scsi_low_bus_release(slp, ti); 300567468Snon scsi_low_init_msgsys(slp, ti); 300667468Snon } 300767468Snon 300879697Snon if (topcb != NULL) 300979697Snon { 301079697Snon topcb->ccb_flags |= CCB_STARTQ; 301179697Snon TAILQ_INSERT_HEAD(&slp->sl_start, topcb, ccb_chain); 301279697Snon } 301379697Snon 301479697Snon slp->sl_disc = 0; 301579697Snon slp->sl_retry_sel = 0; 301667468Snon slp->sl_flags &= ~HW_PDMASTART; 301767468Snon} 301867468Snon 301967468Snon/* misc */ 302067468Snonstatic int tw_pos; 302167468Snonstatic char tw_chars[] = "|/-\\"; 302279697Snon#define TWIDDLEWAIT 10000 302367468Snon 302467468Snonstatic void 302567468Snonscsi_low_twiddle_wait(void) 302667468Snon{ 302767468Snon 302867468Snon cnputc('\b'); 302967468Snon cnputc(tw_chars[tw_pos++]); 303067468Snon tw_pos %= (sizeof(tw_chars) - 1); 303179697Snon SCSI_LOW_DELAY(TWIDDLEWAIT); 303267468Snon} 303367468Snon 303467468Snonvoid 303567468Snonscsi_low_bus_reset(slp) 303667468Snon struct scsi_low_softc *slp; 303767468Snon{ 303867468Snon int i; 303967468Snon 304067468Snon (*slp->sl_funcs->scsi_low_bus_reset) (slp); 304167468Snon 304267468Snon printf("%s: try to reset scsi bus ", slp->sl_xname); 304367468Snon for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++) 304467468Snon scsi_low_twiddle_wait(); 304567468Snon cnputc('\b'); 304667468Snon printf("\n"); 304767468Snon} 304867468Snon 304967468Snonint 305067468Snonscsi_low_restart(slp, flags, s) 305167468Snon struct scsi_low_softc *slp; 305267468Snon int flags; 305367468Snon u_char *s; 305467468Snon{ 305567468Snon int error; 305667468Snon 305767468Snon if (s != NULL) 305867468Snon printf("%s: scsi bus restart. reason: %s\n", slp->sl_xname, s); 305967468Snon 306067468Snon if ((error = scsi_low_init(slp, flags)) != 0) 306167468Snon return error; 306267468Snon 306367468Snon scsi_low_start(slp); 306467468Snon return 0; 306567468Snon} 306667468Snon 306767468Snon/************************************************************** 306867468Snon * disconnect and reselect 306967468Snon **************************************************************/ 307067468Snon#define MSGCMD_LUN(msg) (msg & 0x07) 307167468Snon 307267468Snonstatic struct slccb * 307367468Snonscsi_low_establish_ccb(ti, li, tag) 307467468Snon struct targ_info *ti; 307567468Snon struct lun_info *li; 307667468Snon scsi_low_tag_t tag; 307767468Snon{ 307867468Snon struct scsi_low_softc *slp = ti->ti_sc; 307967468Snon struct slccb *cb; 308067468Snon 308179697Snon if (li == NULL) 308279697Snon return NULL; 308379697Snon 308479697Snon cb = TAILQ_FIRST(&li->li_discq); 308571999Sphk for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain)) 308679697Snon if (cb->ccb_tag == tag) 308767468Snon goto found; 308867468Snon return cb; 308967468Snon 309067468Snon /* 309167468Snon * establish our ccb nexus 309267468Snon */ 309367468Snonfound: 309479697Snon#ifdef SCSI_LOW_DEBUG 309579697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0) 309679697Snon { 309779697Snon printf("%s: nexus(0x%lx) abort check start\n", 309879697Snon slp->sl_xname, (u_long) cb); 309979697Snon cb->ccb_flags |= (CCB_NORETRY | CCB_SILENT); 310079697Snon scsi_low_revoke_ccb(slp, cb, 1); 310179697Snon return NULL; 310279697Snon } 310367468Snon 310479697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id) != 0) 310579697Snon { 310679697Snon if (cb->ccb_omsgoutflag == 0) 310779697Snon scsi_low_ccb_message_assert(cb, SCSI_LOW_MSG_NOOP); 310879697Snon } 310979697Snon#endif /* SCSI_LOW_DEBUG */ 311079697Snon 311179697Snon TAILQ_REMOVE(&li->li_discq, cb, ccb_chain); 311279697Snon cb->ccb_flags &= ~CCB_DISCQ; 311379697Snon slp->sl_Qnexus = cb; 311479697Snon 311567468Snon slp->sl_scp = cb->ccb_sscp; 311667468Snon slp->sl_error |= cb->ccb_error; 311767468Snon 311867468Snon slp->sl_disc --; 311979697Snon ti->ti_disc --; 312067468Snon li->li_disc --; 312167468Snon 312267468Snon /* inform "ccb nexus established" to the host driver */ 312379697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 312479697Snon 312579697Snon /* check msg */ 312679697Snon if (cb->ccb_msgoutflag != 0) 312779697Snon { 312879697Snon scsi_low_ccb_message_exec(slp, cb); 312979697Snon } 313079697Snon 313167468Snon return cb; 313267468Snon} 313367468Snon 313467468Snonstruct targ_info * 313567468Snonscsi_low_reselected(slp, targ) 313667468Snon struct scsi_low_softc *slp; 313767468Snon u_int targ; 313867468Snon{ 313967468Snon struct targ_info *ti; 314079697Snon struct slccb *cb; 314167468Snon u_char *s; 314267468Snon 314367468Snon /* 314467468Snon * Check select vs reselected collision. 314567468Snon */ 314667468Snon 314779697Snon if ((cb = slp->sl_selid) != NULL) 314867468Snon { 314979697Snon scsi_low_arbit_fail(slp, cb); 315067468Snon#ifdef SCSI_LOW_STATICS 315167468Snon scsi_low_statics.nexus_conflict ++; 315267468Snon#endif /* SCSI_LOW_STATICS */ 315367468Snon } 315479697Snon 315579697Snon /* 315679697Snon * Check if no current active nexus. 315779697Snon */ 315879697Snon if (slp->sl_Tnexus != NULL) 315967468Snon { 316067468Snon s = "host busy"; 316167468Snon goto world_restart; 316267468Snon } 316367468Snon 316467468Snon /* 316567468Snon * Check a valid target id asserted ? 316667468Snon */ 316767468Snon if (targ >= slp->sl_ntargs || targ == slp->sl_hostid) 316867468Snon { 316967468Snon s = "scsi id illegal"; 317067468Snon goto world_restart; 317167468Snon } 317267468Snon 317367468Snon /* 317467468Snon * Check the target scsi status. 317567468Snon */ 317667468Snon ti = slp->sl_ti[targ]; 317779697Snon if (ti->ti_phase != PH_DISC && ti->ti_phase != PH_NULL) 317867468Snon { 317967468Snon s = "phase mismatch"; 318067468Snon goto world_restart; 318167468Snon } 318267468Snon 318367468Snon /* 318479697Snon * Setup init msgsys 318567468Snon */ 318667468Snon slp->sl_error = 0; 318767468Snon scsi_low_init_msgsys(slp, ti); 318867468Snon 318967468Snon /* 319067468Snon * Establish our target nexus 319167468Snon */ 319267468Snon SCSI_LOW_SETUP_PHASE(ti, PH_RESEL); 319379697Snon slp->sl_Tnexus = ti; 319467468Snon#ifdef SCSI_LOW_STATICS 319567468Snon scsi_low_statics.nexus_reselected ++; 319667468Snon#endif /* SCSI_LOW_STATICS */ 319767468Snon return ti; 319867468Snon 319967468Snonworld_restart: 320067468Snon printf("%s: reselect(%x:unknown) %s\n", slp->sl_xname, targ, s); 320167468Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, 320267468Snon "reselect: scsi world confused"); 320367468Snon return NULL; 320467468Snon} 320567468Snon 320667468Snon/************************************************************** 320767468Snon * cmd out pointer setup 320867468Snon **************************************************************/ 320967468Snonint 321067468Snonscsi_low_cmd(slp, ti) 321167468Snon struct scsi_low_softc *slp; 321267468Snon struct targ_info *ti; 321367468Snon{ 321479697Snon struct slccb *cb = slp->sl_Qnexus; 321567468Snon 321679697Snon slp->sl_ph_count ++; 321767468Snon if (cb == NULL) 321867468Snon { 321967468Snon /* 322079697Snon * no ccb, abort! 322167468Snon */ 322267468Snon slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd; 322367468Snon slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd); 322467468Snon slp->sl_scp.scp_datalen = 0; 322567468Snon slp->sl_scp.scp_direction = SCSI_LOW_READ; 322679697Snon slp->sl_error |= FATALIO; 322779697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 322879697Snon SCSI_LOW_INFO(slp, ti, "CMDOUT: ccb nexus not found"); 322979697Snon return EINVAL; 323067468Snon } 323179697Snon else 323267468Snon { 323379697Snon#ifdef SCSI_LOW_DEBUG 323479697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_CMDLNK_CHECK, ti->ti_id)) 323579697Snon { 323679697Snon scsi_low_test_cmdlnk(slp, cb); 323779697Snon } 323879697Snon#endif /* SCSI_LOW_DEBUG */ 323967468Snon } 324067468Snon return 0; 324167468Snon} 324267468Snon 324367468Snon/************************************************************** 324467468Snon * data out pointer setup 324567468Snon **************************************************************/ 324667468Snonint 324767468Snonscsi_low_data(slp, ti, bp, direction) 324867468Snon struct scsi_low_softc *slp; 324967468Snon struct targ_info *ti; 325067468Snon struct buf **bp; 325167468Snon int direction; 325267468Snon{ 325379697Snon struct slccb *cb = slp->sl_Qnexus; 325467468Snon 325579697Snon if (cb != NULL && direction == cb->ccb_sscp.scp_direction) 325667468Snon { 325779697Snon *bp = cb->bp; 325879697Snon return 0; 325967468Snon } 326067468Snon 326179697Snon slp->sl_error |= (FATALIO | PDMAERR); 326279697Snon slp->sl_scp.scp_datalen = 0; 326379697Snon slp->sl_scp.scp_direction = direction; 326479697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 326579697Snon if (ti->ti_ophase != ti->ti_phase) 326667468Snon { 326779697Snon char *s; 326879697Snon 326979697Snon if (cb == NULL) 327079697Snon s = "DATA PHASE: ccb nexus not found"; 327179697Snon else 327279697Snon s = "DATA PHASE: xfer direction mismatch"; 327379697Snon SCSI_LOW_INFO(slp, ti, s); 327467468Snon } 327567468Snon 327679697Snon *bp = NULL; 327779697Snon return EINVAL; 327867468Snon} 327967468Snon 328067468Snon/************************************************************** 328167468Snon * MSG_SYS 328267468Snon **************************************************************/ 328367468Snon#define MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;} 328467468Snon#define MSGIN_PERIOD(ti) ((ti)->ti_msgin[3]) 328567468Snon#define MSGIN_OFFSET(ti) ((ti)->ti_msgin[4]) 328679697Snon#define MSGIN_WIDTHP(ti) ((ti)->ti_msgin[3]) 328767468Snon#define MSGIN_DATA_LAST 0x30 328867468Snon 328992770Salfredstatic int scsi_low_errfunc_synch(struct scsi_low_softc *, u_int); 329092770Salfredstatic int scsi_low_errfunc_wide(struct scsi_low_softc *, u_int); 329192770Salfredstatic int scsi_low_errfunc_identify(struct scsi_low_softc *, u_int); 329292770Salfredstatic int scsi_low_errfunc_qtag(struct scsi_low_softc *, u_int); 329367468Snon 329492770Salfredstatic int scsi_low_msgfunc_synch(struct scsi_low_softc *); 329592770Salfredstatic int scsi_low_msgfunc_wide(struct scsi_low_softc *); 329692770Salfredstatic int scsi_low_msgfunc_identify(struct scsi_low_softc *); 329792770Salfredstatic int scsi_low_msgfunc_abort(struct scsi_low_softc *); 329892770Salfredstatic int scsi_low_msgfunc_qabort(struct scsi_low_softc *); 329992770Salfredstatic int scsi_low_msgfunc_qtag(struct scsi_low_softc *); 330092770Salfredstatic int scsi_low_msgfunc_reset(struct scsi_low_softc *); 330167468Snon 330267468Snonstruct scsi_low_msgout_data { 330367468Snon u_int md_flags; 330467468Snon u_int8_t md_msg; 330592770Salfred int (*md_msgfunc)(struct scsi_low_softc *); 330692770Salfred int (*md_errfunc)(struct scsi_low_softc *, u_int); 330779697Snon#define MSG_RELEASE_ATN 0x0001 330879697Snon u_int md_condition; 330967468Snon}; 331067468Snon 331167468Snonstruct scsi_low_msgout_data scsi_low_msgout_data[] = { 331279697Snon/* 0 */ {SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_reset, NULL, MSG_RELEASE_ATN}, 331379697Snon/* 1 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL, MSG_RELEASE_ATN}, 331479697Snon/* 2 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL, MSG_RELEASE_ATN}, 331579697Snon/* 3 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL, MSG_RELEASE_ATN}, 331679697Snon/* 4 */ {SCSI_LOW_MSG_IDENTIFY, MSG_IDENTIFY, scsi_low_msgfunc_identify, scsi_low_errfunc_identify, 0}, 331779697Snon/* 5 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN}, 331879697Snon/* 6 */ {SCSI_LOW_MSG_TERMIO, MSG_TERM_IO, NULL, NULL, MSG_RELEASE_ATN}, 331979697Snon/* 7 */ {SCSI_LOW_MSG_SIMPLE_QTAG, MSG_SIMPLE_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 332079697Snon/* 8 */ {SCSI_LOW_MSG_ORDERED_QTAG, MSG_ORDERED_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 332179697Snon/* 9 */{SCSI_LOW_MSG_HEAD_QTAG, MSG_HEAD_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 332279697Snon/* 10 */ {SCSI_LOW_MSG_ABORT_QTAG, MSG_ABORT_QTAG, scsi_low_msgfunc_qabort, NULL, MSG_RELEASE_ATN}, 332379697Snon/* 11 */ {SCSI_LOW_MSG_CLEAR_QTAG, MSG_CLEAR_QTAG, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN}, 332479697Snon/* 12 */{SCSI_LOW_MSG_WIDE, MSG_EXTEND, scsi_low_msgfunc_wide, scsi_low_errfunc_wide, MSG_RELEASE_ATN}, 332579697Snon/* 13 */{SCSI_LOW_MSG_SYNCH, MSG_EXTEND, scsi_low_msgfunc_synch, scsi_low_errfunc_synch, MSG_RELEASE_ATN}, 332679697Snon/* 14 */{SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL, MSG_RELEASE_ATN}, 332779697Snon/* 15 */{SCSI_LOW_MSG_ALL, 0}, 332867468Snon}; 332967468Snon 333092770Salfredstatic int scsi_low_msginfunc_ext(struct scsi_low_softc *); 333192770Salfredstatic int scsi_low_synch(struct scsi_low_softc *); 333292770Salfredstatic int scsi_low_wide(struct scsi_low_softc *); 333392770Salfredstatic int scsi_low_msginfunc_msg_reject(struct scsi_low_softc *); 333492770Salfredstatic int scsi_low_msginfunc_rejop(struct scsi_low_softc *); 333592770Salfredstatic int scsi_low_msginfunc_rp(struct scsi_low_softc *); 333692770Salfredstatic int scsi_low_msginfunc_sdp(struct scsi_low_softc *); 333792770Salfredstatic int scsi_low_msginfunc_disc(struct scsi_low_softc *); 333892770Salfredstatic int scsi_low_msginfunc_cc(struct scsi_low_softc *); 333992770Salfredstatic int scsi_low_msginfunc_lcc(struct scsi_low_softc *); 334092770Salfredstatic int scsi_low_msginfunc_parity(struct scsi_low_softc *); 334192770Salfredstatic int scsi_low_msginfunc_noop(struct scsi_low_softc *); 334292770Salfredstatic int scsi_low_msginfunc_simple_qtag(struct scsi_low_softc *); 334392770Salfredstatic int scsi_low_msginfunc_i_wide_residue(struct scsi_low_softc *); 334467468Snon 334567468Snonstruct scsi_low_msgin_data { 334667468Snon u_int md_len; 334792770Salfred int (*md_msgfunc)(struct scsi_low_softc *); 334867468Snon}; 334967468Snon 335067468Snonstruct scsi_low_msgin_data scsi_low_msgin_data[] = { 335167468Snon/* 0 */ {1, scsi_low_msginfunc_cc}, 335267468Snon/* 1 */ {2, scsi_low_msginfunc_ext}, 335367468Snon/* 2 */ {1, scsi_low_msginfunc_sdp}, 335479697Snon/* 3 */ {1, scsi_low_msginfunc_rp}, 335567468Snon/* 4 */ {1, scsi_low_msginfunc_disc}, 335667468Snon/* 5 */ {1, scsi_low_msginfunc_rejop}, 335767468Snon/* 6 */ {1, scsi_low_msginfunc_rejop}, 335867468Snon/* 7 */ {1, scsi_low_msginfunc_msg_reject}, 335967468Snon/* 8 */ {1, scsi_low_msginfunc_noop}, 336067468Snon/* 9 */ {1, scsi_low_msginfunc_parity}, 336179697Snon/* a */ {1, scsi_low_msginfunc_lcc}, 336279697Snon/* b */ {1, scsi_low_msginfunc_lcc}, 336367468Snon/* c */ {1, scsi_low_msginfunc_rejop}, 336467468Snon/* d */ {2, scsi_low_msginfunc_rejop}, 336567468Snon/* e */ {1, scsi_low_msginfunc_rejop}, 336667468Snon/* f */ {1, scsi_low_msginfunc_rejop}, 336767468Snon/* 0x10 */ {1, scsi_low_msginfunc_rejop}, 336867468Snon/* 0x11 */ {1, scsi_low_msginfunc_rejop}, 336967468Snon/* 0x12 */ {1, scsi_low_msginfunc_rejop}, 337067468Snon/* 0x13 */ {1, scsi_low_msginfunc_rejop}, 337167468Snon/* 0x14 */ {1, scsi_low_msginfunc_rejop}, 337267468Snon/* 0x15 */ {1, scsi_low_msginfunc_rejop}, 337367468Snon/* 0x16 */ {1, scsi_low_msginfunc_rejop}, 337467468Snon/* 0x17 */ {1, scsi_low_msginfunc_rejop}, 337567468Snon/* 0x18 */ {1, scsi_low_msginfunc_rejop}, 337667468Snon/* 0x19 */ {1, scsi_low_msginfunc_rejop}, 337767468Snon/* 0x1a */ {1, scsi_low_msginfunc_rejop}, 337867468Snon/* 0x1b */ {1, scsi_low_msginfunc_rejop}, 337967468Snon/* 0x1c */ {1, scsi_low_msginfunc_rejop}, 338067468Snon/* 0x1d */ {1, scsi_low_msginfunc_rejop}, 338167468Snon/* 0x1e */ {1, scsi_low_msginfunc_rejop}, 338267468Snon/* 0x1f */ {1, scsi_low_msginfunc_rejop}, 338379697Snon/* 0x20 */ {2, scsi_low_msginfunc_simple_qtag}, 338467468Snon/* 0x21 */ {2, scsi_low_msginfunc_rejop}, 338567468Snon/* 0x22 */ {2, scsi_low_msginfunc_rejop}, 338679697Snon/* 0x23 */ {2, scsi_low_msginfunc_i_wide_residue}, 338767468Snon/* 0x24 */ {2, scsi_low_msginfunc_rejop}, 338867468Snon/* 0x25 */ {2, scsi_low_msginfunc_rejop}, 338967468Snon/* 0x26 */ {2, scsi_low_msginfunc_rejop}, 339067468Snon/* 0x27 */ {2, scsi_low_msginfunc_rejop}, 339167468Snon/* 0x28 */ {2, scsi_low_msginfunc_rejop}, 339267468Snon/* 0x29 */ {2, scsi_low_msginfunc_rejop}, 339367468Snon/* 0x2a */ {2, scsi_low_msginfunc_rejop}, 339467468Snon/* 0x2b */ {2, scsi_low_msginfunc_rejop}, 339567468Snon/* 0x2c */ {2, scsi_low_msginfunc_rejop}, 339667468Snon/* 0x2d */ {2, scsi_low_msginfunc_rejop}, 339767468Snon/* 0x2e */ {2, scsi_low_msginfunc_rejop}, 339867468Snon/* 0x2f */ {2, scsi_low_msginfunc_rejop}, 339967468Snon/* 0x30 */ {1, scsi_low_msginfunc_rejop} /* default rej op */ 340067468Snon}; 340167468Snon 340267468Snon/************************************************************** 340367468Snon * msgout 340467468Snon **************************************************************/ 340567468Snonstatic int 340679697Snonscsi_low_msgfunc_synch(slp) 340779697Snon struct scsi_low_softc *slp; 340867468Snon{ 340979697Snon struct targ_info *ti = slp->sl_Tnexus; 341067468Snon int ptr = ti->ti_msgoutlen; 341167468Snon 341267468Snon ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN; 341367468Snon ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE; 341473025Snon ti->ti_msgoutstr[ptr + 3] = ti->ti_maxsynch.period; 341573025Snon ti->ti_msgoutstr[ptr + 4] = ti->ti_maxsynch.offset; 341667468Snon return MSG_EXTEND_SYNCHLEN + 2; 341767468Snon} 341867468Snon 341967468Snonstatic int 342079697Snonscsi_low_msgfunc_wide(slp) 342179697Snon struct scsi_low_softc *slp; 342267468Snon{ 342379697Snon struct targ_info *ti = slp->sl_Tnexus; 342467468Snon int ptr = ti->ti_msgoutlen; 342567468Snon 342667468Snon ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN; 342767468Snon ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE; 342873025Snon ti->ti_msgoutstr[ptr + 3] = ti->ti_width; 342967468Snon return MSG_EXTEND_WIDELEN + 2; 343067468Snon} 343167468Snon 343267468Snonstatic int 343379697Snonscsi_low_msgfunc_identify(slp) 343479697Snon struct scsi_low_softc *slp; 343567468Snon{ 343679697Snon struct targ_info *ti = slp->sl_Tnexus; 343779697Snon struct lun_info *li = slp->sl_Lnexus; 343879697Snon struct slccb *cb = slp->sl_Qnexus; 343979697Snon int ptr = ti->ti_msgoutlen; 344079697Snon u_int8_t msg; 344167468Snon 344279697Snon msg = MSG_IDENTIFY; 344379697Snon if (cb == NULL) 344467468Snon { 344579697Snon slp->sl_error |= FATALIO; 344679697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 344779697Snon SCSI_LOW_INFO(slp, ti, "MSGOUT: nexus unknown"); 344867468Snon } 344967468Snon else 345067468Snon { 345179697Snon if (scsi_low_is_disconnect_ok(cb) != 0) 345279697Snon msg |= (MSG_IDENTIFY_DISCPRIV | li->li_lun); 345379697Snon else 345479697Snon msg |= li->li_lun; 345579697Snon 345679697Snon if (ti->ti_phase == PH_MSGOUT) 345779697Snon { 345879697Snon (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp); 345979697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 346079697Snon { 346179697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 346279697Snon } 346379697Snon } 346467468Snon } 346579697Snon ti->ti_msgoutstr[ptr + 0] = msg; 346667468Snon return 1; 346767468Snon} 346867468Snon 346967468Snonstatic int 347079697Snonscsi_low_msgfunc_abort(slp) 347179697Snon struct scsi_low_softc *slp; 347267468Snon{ 347367468Snon 347479697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_ABORT); 347579697Snon return 1; 347679697Snon} 347779697Snon 347879697Snonstatic int 347979697Snonscsi_low_msgfunc_qabort(slp) 348079697Snon struct scsi_low_softc *slp; 348179697Snon{ 348279697Snon 348379697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_TERM); 348479697Snon return 1; 348579697Snon} 348679697Snon 348779697Snonstatic int 348879697Snonscsi_low_msgfunc_reset(slp) 348979697Snon struct scsi_low_softc *slp; 349079697Snon{ 349179697Snon 349279697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_RESET); 349379697Snon return 1; 349479697Snon} 349579697Snon 349679697Snonstatic int 349779697Snonscsi_low_msgfunc_qtag(slp) 349879697Snon struct scsi_low_softc *slp; 349979697Snon{ 350079697Snon struct targ_info *ti = slp->sl_Tnexus; 350179697Snon struct slccb *cb = slp->sl_Qnexus; 350279697Snon int ptr = ti->ti_msgoutlen; 350379697Snon 350479697Snon if (cb == NULL || cb->ccb_tag == SCSI_LOW_UNKTAG) 350567468Snon { 350667468Snon ti->ti_msgoutstr[ptr + 0] = MSG_NOOP; 350767468Snon return 1; 350867468Snon } 350967468Snon else 351067468Snon { 351179697Snon ti->ti_msgoutstr[ptr + 1] = (u_int8_t) cb->ccb_tag; 351279697Snon if (ti->ti_phase == PH_MSGOUT) 351379697Snon { 351479697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 351579697Snon } 351667468Snon } 351779697Snon return 2; 351867468Snon} 351967468Snon 352067468Snon/* 352167468Snon * The following functions are called when targets give unexpected 352267468Snon * responces in msgin (after msgout). 352367468Snon */ 352467468Snonstatic int 352579697Snonscsi_low_errfunc_identify(slp, msgflags) 352679697Snon struct scsi_low_softc *slp; 352767468Snon u_int msgflags; 352867468Snon{ 352967468Snon 353079697Snon if (slp->sl_Lnexus != NULL) 353179697Snon { 353279697Snon slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_DISC; 353379697Snon scsi_low_calcf_lun(slp->sl_Lnexus); 353479697Snon } 353567468Snon return 0; 353667468Snon} 353767468Snon 353867468Snonstatic int 353979697Snonscsi_low_errfunc_synch(slp, msgflags) 354079697Snon struct scsi_low_softc *slp; 354167468Snon u_int msgflags; 354267468Snon{ 354379697Snon struct targ_info *ti = slp->sl_Tnexus; 354467468Snon 354567468Snon MSGIN_PERIOD(ti) = 0; 354667468Snon MSGIN_OFFSET(ti) = 0; 354779697Snon scsi_low_synch(slp); 354867468Snon return 0; 354967468Snon} 355067468Snon 355167468Snonstatic int 355279697Snonscsi_low_errfunc_wide(slp, msgflags) 355379697Snon struct scsi_low_softc *slp; 355467468Snon u_int msgflags; 355567468Snon{ 355679697Snon struct targ_info *ti = slp->sl_Tnexus; 355779697Snon 355879697Snon MSGIN_WIDTHP(ti) = 0; 355979697Snon scsi_low_wide(slp); 356067468Snon return 0; 356167468Snon} 356267468Snon 356379697Snonstatic int 356479697Snonscsi_low_errfunc_qtag(slp, msgflags) 356579697Snon struct scsi_low_softc *slp; 356679697Snon u_int msgflags; 356779697Snon{ 356879697Snon 356979697Snon if ((msgflags & SCSI_LOW_MSG_REJECT) != 0) 357079697Snon { 357179697Snon if (slp->sl_Qnexus != NULL) 357279697Snon { 357379697Snon scsi_low_deactivate_qtag(slp->sl_Qnexus); 357479697Snon } 357579697Snon if (slp->sl_Lnexus != NULL) 357679697Snon { 357779697Snon slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_QTAG; 357879697Snon scsi_low_calcf_lun(slp->sl_Lnexus); 357979697Snon } 358079697Snon printf("%s: scsi_low: qtag msg rejected\n", slp->sl_xname); 358179697Snon } 358279697Snon return 0; 358379697Snon} 358479697Snon 358579697Snon 358667468Snonint 358779697Snonscsi_low_msgout(slp, ti, fl) 358867468Snon struct scsi_low_softc *slp; 358967468Snon struct targ_info *ti; 359079697Snon u_int fl; 359167468Snon{ 359267468Snon struct scsi_low_msgout_data *mdp; 359367468Snon int len = 0; 359467468Snon 359579697Snon#ifdef SCSI_LOW_DIAGNOSTIC 359679697Snon if (ti != slp->sl_Tnexus) 359779697Snon { 359879697Snon scsi_low_print(slp, NULL); 359979697Snon panic("scsi_low_msgout: Target nexus inconsistent"); 360079697Snon } 360179697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 360279697Snon 360379697Snon slp->sl_ph_count ++; 360479697Snon if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES) 360579697Snon { 360679697Snon printf("%s: too many phase changes\n", slp->sl_xname); 360779697Snon slp->sl_error |= FATALIO; 360879697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 360979697Snon } 361079697Snon 361167468Snon /* STEP I. 361267468Snon * Scsi phase changes. 361367468Snon * Previously msgs asserted are accepted by our target or 361467468Snon * processed by scsi_low_msgin. 361567468Snon * Thus clear all saved informations. 361667468Snon */ 361779697Snon if ((fl & SCSI_LOW_MSGOUT_INIT) != 0) 361867468Snon { 361967468Snon ti->ti_omsgflags = 0; 362067468Snon ti->ti_emsgflags = 0; 362167468Snon } 362279697Snon else if (slp->sl_atten == 0) 362379697Snon { 362467468Snon /* STEP II. 362567468Snon * We did not assert attention, however still our target required 362667468Snon * msgs. Resend previous msgs. 362767468Snon */ 362867468Snon ti->ti_msgflags |= ti->ti_omsgflags; 362979697Snon ti->ti_omsgflags = 0; 363067468Snon#ifdef SCSI_LOW_DIAGNOSTIC 363167468Snon printf("%s: scsi_low_msgout: retry msgout\n", slp->sl_xname); 363267468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 363367468Snon } 363467468Snon 363567468Snon /* STEP III. 363679697Snon * We have no msgs. send MSG_NOOP (OK?) 363767468Snon */ 363879697Snon if (scsi_low_is_msgout_continue(ti, 0) == 0) 363967468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0); 364067468Snon 364167468Snon /* STEP IV. 364267468Snon * Process all msgs 364367468Snon */ 364467468Snon ti->ti_msgoutlen = 0; 364579697Snon slp->sl_clear_atten = 0; 364667468Snon mdp = &scsi_low_msgout_data[0]; 364767468Snon for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) 364867468Snon { 364967468Snon if ((ti->ti_msgflags & mdp->md_flags) != 0) 365067468Snon { 365167468Snon ti->ti_omsgflags |= mdp->md_flags; 365267468Snon ti->ti_msgflags &= ~mdp->md_flags; 365367468Snon ti->ti_emsgflags = mdp->md_flags; 365467468Snon 365567468Snon ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg; 365667468Snon if (mdp->md_msgfunc != NULL) 365779697Snon len = (*mdp->md_msgfunc) (slp); 365867468Snon else 365967468Snon len = 1; 366067468Snon 366179697Snon#ifdef SCSI_LOW_DIAGNOSTIC 366279697Snon scsi_low_msg_log_write(&ti->ti_log_msgout, 366379697Snon &ti->ti_msgoutstr[ti->ti_msgoutlen], len); 366479697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 366579697Snon 366667468Snon ti->ti_msgoutlen += len; 366779697Snon if ((mdp->md_condition & MSG_RELEASE_ATN) != 0) 366879697Snon { 366979697Snon slp->sl_clear_atten = 1; 367079697Snon break; 367179697Snon } 367279697Snon 367379697Snon if ((fl & SCSI_LOW_MSGOUT_UNIFY) == 0 || 367467468Snon ti->ti_msgflags == 0) 367567468Snon break; 367679697Snon 367767468Snon if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5) 367867468Snon break; 367967468Snon } 368067468Snon } 368167468Snon 368279697Snon if (scsi_low_is_msgout_continue(ti, 0) == 0) 368379697Snon slp->sl_clear_atten = 1; 368467468Snon 368567468Snon return ti->ti_msgoutlen; 368667468Snon} 368767468Snon 368867468Snon/************************************************************** 368967468Snon * msgin 369067468Snon **************************************************************/ 369167468Snonstatic int 369279697Snonscsi_low_msginfunc_noop(slp) 369379697Snon struct scsi_low_softc *slp; 369467468Snon{ 369567468Snon 369667468Snon return 0; 369767468Snon} 369867468Snon 369967468Snonstatic int 370079697Snonscsi_low_msginfunc_rejop(slp) 370179697Snon struct scsi_low_softc *slp; 370267468Snon{ 370379697Snon struct targ_info *ti = slp->sl_Tnexus; 370467468Snon u_int8_t msg = ti->ti_msgin[0]; 370567468Snon 370679697Snon printf("%s: MSGIN: msg 0x%x rejected\n", slp->sl_xname, (u_int) msg); 370767468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 370867468Snon return 0; 370967468Snon} 371067468Snon 371167468Snonstatic int 371279697Snonscsi_low_msginfunc_cc(slp) 371379697Snon struct scsi_low_softc *slp; 371467468Snon{ 371579697Snon struct lun_info *li; 371667468Snon 371767468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); 371879697Snon 371979697Snon /* validate status */ 372079697Snon if (slp->sl_Qnexus == NULL) 372179697Snon return ENOENT; 372279697Snon 372379697Snon slp->sl_Qnexus->ccb_sscp.scp_status = slp->sl_scp.scp_status; 372479697Snon li = slp->sl_Lnexus; 372579697Snon switch (slp->sl_scp.scp_status) 372679697Snon { 372779697Snon case ST_GOOD: 372879697Snon li->li_maxnqio = li->li_maxnexus; 372979697Snon break; 373079697Snon 373179697Snon case ST_CHKCOND: 373279697Snon li->li_maxnqio = 0; 373379697Snon if (li->li_qflags & SCSI_LOW_QFLAG_CA_QCLEAR) 373479697Snon scsi_low_reset_nexus_lun(slp, li, 0); 373579697Snon break; 373679697Snon 373779697Snon case ST_BUSY: 373879697Snon li->li_maxnqio = 0; 373979697Snon break; 374079697Snon 374179697Snon case ST_QUEFULL: 374279697Snon if (li->li_maxnexus >= li->li_nqio) 374379697Snon li->li_maxnexus = li->li_nqio - 1; 374479697Snon li->li_maxnqio = li->li_maxnexus; 374579697Snon break; 374679697Snon 374779697Snon case ST_INTERGOOD: 374879697Snon case ST_INTERMET: 374979697Snon slp->sl_error |= MSGERR; 375079697Snon break; 375179697Snon 375279697Snon default: 375379697Snon break; 375479697Snon } 375567468Snon return 0; 375667468Snon} 375767468Snon 375867468Snonstatic int 375979697Snonscsi_low_msginfunc_lcc(slp) 376079697Snon struct scsi_low_softc *slp; 376179697Snon{ 376267468Snon struct targ_info *ti; 376379697Snon struct lun_info *li; 376479697Snon struct slccb *ncb, *cb; 376579697Snon 376679697Snon ti = slp->sl_Tnexus; 376779697Snon li = slp->sl_Lnexus; 376879697Snon if ((cb = slp->sl_Qnexus) == NULL) 376979697Snon goto bad; 377079697Snon 377179697Snon cb->ccb_sscp.scp_status = slp->sl_scp.scp_status; 377279697Snon switch (slp->sl_scp.scp_status) 377379697Snon { 377479697Snon case ST_INTERGOOD: 377579697Snon case ST_INTERMET: 377679697Snon li->li_maxnqio = li->li_maxnexus; 377779697Snon break; 377879697Snon 377979697Snon default: 378079697Snon slp->sl_error |= MSGERR; 378179697Snon break; 378279697Snon } 378379697Snon 378479697Snon if ((li->li_flags & SCSI_LOW_LINK) == 0) 378579697Snon goto bad; 378679697Snon 378779697Snon cb->ccb_error |= slp->sl_error; 378879697Snon if (cb->ccb_error != 0) 378979697Snon goto bad; 379079697Snon 379179697Snon for (ncb = TAILQ_FIRST(&slp->sl_start); ncb != NULL; 379279697Snon ncb = TAILQ_NEXT(ncb, ccb_chain)) 379379697Snon { 379479697Snon if (ncb->li == li) 379579697Snon goto cmd_link_start; 379679697Snon } 379779697Snon 379879697Snon 379979697Snonbad: 380079697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_LCTERM); 380179697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 380279697Snon return EIO; 380379697Snon 380479697Snoncmd_link_start: 380579697Snon ncb->ccb_flags &= ~CCB_STARTQ; 380679697Snon TAILQ_REMOVE(&slp->sl_start, ncb, ccb_chain); 380779697Snon 380879697Snon scsi_low_dealloc_qtag(ncb); 380979697Snon ncb->ccb_tag = cb->ccb_tag; 381079697Snon ncb->ccb_otag = cb->ccb_otag; 381179697Snon cb->ccb_tag = SCSI_LOW_UNKTAG; 381279697Snon cb->ccb_otag = SCSI_LOW_UNKTAG; 381379697Snon if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY) 3814106890Simp panic("%s: linked ccb retried", slp->sl_xname); 381579697Snon 381679697Snon slp->sl_Qnexus = ncb; 381779697Snon slp->sl_ph_count = 0; 381879697Snon 381979697Snon ncb->ccb_error = 0; 382079697Snon ncb->ccb_datalen = -1; 382179697Snon ncb->ccb_scp.scp_status = ST_UNKNOWN; 382279697Snon ncb->ccb_flags &= ~CCB_INTERNAL; 382379697Snon 382479697Snon scsi_low_init_msgsys(slp, ti); 382579697Snon 382679697Snon (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, ncb); 382779697Snon 382879697Snon if (ncb->ccb_tcmax < SCSI_LOW_MIN_TOUT) 382979697Snon ncb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 383079697Snon ncb->ccb_tc = ncb->ccb_tcmax; 383179697Snon 383279697Snon /* setup saved scsi data pointer */ 383379697Snon ncb->ccb_sscp = ncb->ccb_scp; 383479697Snon slp->sl_scp = ncb->ccb_sscp; 383579697Snon slp->sl_error = ncb->ccb_error; 383679697Snon 383779697Snon#ifdef SCSI_LOW_DIAGNOSTIC 383879697Snon scsi_low_msg_log_init(&ti->ti_log_msgin); 383979697Snon scsi_low_msg_log_init(&ti->ti_log_msgout); 384079697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 384179697Snon return EJUSTRETURN; 384279697Snon} 384379697Snon 384479697Snonstatic int 384579697Snonscsi_low_msginfunc_disc(slp) 384679697Snon struct scsi_low_softc *slp; 384767468Snon{ 384867468Snon 384967468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC); 385067468Snon return 0; 385167468Snon} 385267468Snon 385367468Snonstatic int 385479697Snonscsi_low_msginfunc_sdp(slp) 385579697Snon struct scsi_low_softc *slp; 385667468Snon{ 385779697Snon struct slccb *cb = slp->sl_Qnexus; 385867468Snon 385979697Snon if (cb != NULL) 386079697Snon { 386179697Snon cb->ccb_sscp.scp_datalen = slp->sl_scp.scp_datalen; 386279697Snon cb->ccb_sscp.scp_data = slp->sl_scp.scp_data; 386379697Snon } 386467468Snon else 386579697Snon scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0); 386667468Snon return 0; 386767468Snon} 386867468Snon 386967468Snonstatic int 387079697Snonscsi_low_msginfunc_rp(slp) 387179697Snon struct scsi_low_softc *slp; 387267468Snon{ 387367468Snon 387479697Snon if (slp->sl_Qnexus != NULL) 387579697Snon slp->sl_scp = slp->sl_Qnexus->ccb_sscp; 387667468Snon else 387779697Snon scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0); 387867468Snon return 0; 387967468Snon} 388067468Snon 388167468Snonstatic int 388279697Snonscsi_low_synch(slp) 388379697Snon struct scsi_low_softc *slp; 388467468Snon{ 388579697Snon struct targ_info *ti = slp->sl_Tnexus; 388679697Snon u_int period = 0, offset = 0, speed; 388767468Snon u_char *s; 388867468Snon int error; 388967468Snon 389079697Snon if ((MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period && 389179697Snon MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset) || 389279697Snon MSGIN_OFFSET(ti) == 0) 389367468Snon { 389467468Snon if ((offset = MSGIN_OFFSET(ti)) != 0) 389567468Snon period = MSGIN_PERIOD(ti); 389667468Snon s = offset ? "synchronous" : "async"; 389767468Snon } 389867468Snon else 389967468Snon { 390067468Snon /* XXX: 390167468Snon * Target seems to be brain damaged. 390267468Snon * Force async transfer. 390367468Snon */ 390473025Snon ti->ti_maxsynch.period = 0; 390573025Snon ti->ti_maxsynch.offset = 0; 390667468Snon printf("%s: target brain damaged. async transfer\n", 390767468Snon slp->sl_xname); 390867468Snon return EINVAL; 390967468Snon } 391067468Snon 391173025Snon ti->ti_maxsynch.period = period; 391273025Snon ti->ti_maxsynch.offset = offset; 391367468Snon 391467468Snon error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH); 391567468Snon if (error != 0) 391667468Snon { 391767468Snon /* XXX: 391867468Snon * Current period and offset are not acceptable 391967468Snon * for our adapter. 392067468Snon * The adapter changes max synch and max offset. 392167468Snon */ 392267468Snon printf("%s: synch neg failed. retry synch msg neg ...\n", 392367468Snon slp->sl_xname); 392467468Snon return error; 392567468Snon } 392667468Snon 392779697Snon ti->ti_osynch = ti->ti_maxsynch; 392879697Snon if (offset > 0) 392979697Snon { 393079697Snon ti->ti_setup_msg_done |= SCSI_LOW_MSG_SYNCH; 393179697Snon } 393279697Snon 393367468Snon /* inform data */ 393479697Snon if ((slp->sl_show_result & SHOW_SYNCH_NEG) != 0) 393567468Snon { 393679697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 393779697Snon struct slccb *cb = slp->sl_Qnexus; 393879697Snon 393979697Snon if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0) 394079697Snon return 0; 394179697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 394279697Snon 394379697Snon printf("%s(%d:*): <%s> offset %d period %dns ", 394479697Snon slp->sl_xname, ti->ti_id, s, offset, period * 4); 394579697Snon 394679697Snon if (period != 0) 394779697Snon { 394879697Snon speed = 1000 * 10 / (period * 4); 394979697Snon printf("%d.%d M/s", speed / 10, speed % 10); 395079697Snon } 395179697Snon printf("\n"); 395267468Snon } 395379697Snon return 0; 395479697Snon} 395567468Snon 395679697Snonstatic int 395779697Snonscsi_low_wide(slp) 395879697Snon struct scsi_low_softc *slp; 395979697Snon{ 396079697Snon struct targ_info *ti = slp->sl_Tnexus; 396179697Snon int error; 396279697Snon 396379697Snon ti->ti_width = MSGIN_WIDTHP(ti); 396479697Snon error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_WIDE); 396579697Snon if (error != 0) 396679697Snon { 396779697Snon /* XXX: 396879697Snon * Current width is not acceptable for our adapter. 396979697Snon * The adapter changes max width. 397079697Snon */ 397179697Snon printf("%s: wide neg failed. retry wide msg neg ...\n", 397279697Snon slp->sl_xname); 397379697Snon return error; 397479697Snon } 397579697Snon 397679697Snon ti->ti_owidth = ti->ti_width; 397779697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 397879697Snon { 397979697Snon ti->ti_setup_msg_done |= 398079697Snon (SCSI_LOW_MSG_SYNCH | SCSI_LOW_MSG_WIDE); 398179697Snon } 398279697Snon 398379697Snon /* inform data */ 398479697Snon if ((slp->sl_show_result & SHOW_WIDE_NEG) != 0) 398579697Snon { 398679697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 398779697Snon struct slccb *cb = slp->sl_Qnexus; 398879697Snon 398979697Snon if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0) 399079697Snon return 0; 399179697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 399279697Snon 399379697Snon printf("%s(%d:*): transfer width %d bits\n", 399479697Snon slp->sl_xname, ti->ti_id, 1 << (3 + ti->ti_width)); 399579697Snon } 399667468Snon return 0; 399767468Snon} 399867468Snon 399967468Snonstatic int 400079697Snonscsi_low_msginfunc_simple_qtag(slp) 400179697Snon struct scsi_low_softc *slp; 400267468Snon{ 400379697Snon struct targ_info *ti = slp->sl_Tnexus; 400479697Snon scsi_low_tag_t etag = (scsi_low_tag_t) ti->ti_msgin[1]; 400579697Snon 400679697Snon if (slp->sl_Qnexus != NULL) 400779697Snon { 400879697Snon if (slp->sl_Qnexus->ccb_tag != etag) 400979697Snon { 401079697Snon slp->sl_error |= FATALIO; 401179697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 401279697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: qtag mismatch"); 401379697Snon } 401479697Snon } 401579697Snon else if (scsi_low_establish_ccb(ti, slp->sl_Lnexus, etag) == NULL) 401679697Snon { 401779697Snon#ifdef SCSI_LOW_DEBUG 401879697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id)) 401979697Snon return 0; 402079697Snon#endif /* SCSI_LOW_DEBUG */ 402179697Snon 402279697Snon slp->sl_error |= FATALIO; 402379697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT_QTAG, 0); 402479697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: taged ccb not found"); 402579697Snon } 402679697Snon return 0; 402779697Snon} 402879697Snon 402979697Snonstatic int 403079697Snonscsi_low_msginfunc_i_wide_residue(slp) 403179697Snon struct scsi_low_softc *slp; 403279697Snon{ 403379697Snon struct targ_info *ti = slp->sl_Tnexus; 403479697Snon struct slccb *cb = slp->sl_Qnexus; 403579697Snon int res = (int) ti->ti_msgin[1]; 403679697Snon 403779697Snon if (cb == NULL || res <= 0 || 403879697Snon (ti->ti_width == SCSI_LOW_BUS_WIDTH_16 && res > 1) || 403979697Snon (ti->ti_width == SCSI_LOW_BUS_WIDTH_32 && res > 3)) 404079697Snon return EINVAL; 404179697Snon 404279697Snon if (slp->sl_scp.scp_datalen + res > cb->ccb_scp.scp_datalen) 404379697Snon return EINVAL; 404479697Snon 404579697Snon slp->sl_scp.scp_datalen += res; 404679697Snon slp->sl_scp.scp_data -= res; 404779697Snon scsi_low_data_finish(slp); 404879697Snon return 0; 404979697Snon} 405079697Snon 405179697Snonstatic int 405279697Snonscsi_low_msginfunc_ext(slp) 405379697Snon struct scsi_low_softc *slp; 405479697Snon{ 405579697Snon struct slccb *cb = slp->sl_Qnexus; 405679697Snon struct lun_info *li = slp->sl_Lnexus; 405779697Snon struct targ_info *ti = slp->sl_Tnexus; 405867468Snon int count, retry; 405967468Snon u_int32_t *ptr; 406067468Snon 406167468Snon if (ti->ti_msginptr == 2) 406267468Snon { 406367468Snon ti->ti_msginlen = ti->ti_msgin[1] + 2; 406467468Snon return 0; 406567468Snon } 406667468Snon 406767468Snon switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2])) 406867468Snon { 406967468Snon case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE): 407067468Snon if (cb == NULL) 407167468Snon break; 407267468Snon 407367468Snon ptr = (u_int32_t *)(&ti->ti_msgin[3]); 407467468Snon count = (int) htonl((long) (*ptr)); 407567468Snon if(slp->sl_scp.scp_datalen - count < 0 || 407667468Snon slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen) 407767468Snon break; 407867468Snon 407967468Snon slp->sl_scp.scp_datalen -= count; 408067468Snon slp->sl_scp.scp_data += count; 408167468Snon return 0; 408267468Snon 408367468Snon case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE): 408467468Snon if (li == NULL) 408567468Snon break; 408667468Snon 408779697Snon retry = scsi_low_synch(slp); 408867468Snon if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0) 408967468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0); 409079697Snon 409179697Snon#ifdef SCSI_LOW_DEBUG 409279697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id)) 409379697Snon { 409479697Snon scsi_low_test_atten(slp, ti, SCSI_LOW_MSG_SYNCH); 409579697Snon } 409679697Snon#endif /* SCSI_LOW_DEBUG */ 409767468Snon return 0; 409867468Snon 409967468Snon case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE): 410067468Snon if (li == NULL) 410167468Snon break; 410267468Snon 410379697Snon retry = scsi_low_wide(slp); 410479697Snon if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_WIDE) == 0) 410579697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0); 410679697Snon 410767468Snon return 0; 410867468Snon 410967468Snon default: 411067468Snon break; 411167468Snon } 411267468Snon 411367468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 411467468Snon return EINVAL; 411567468Snon} 411667468Snon 411767468Snonstatic int 411879697Snonscsi_low_msginfunc_parity(slp) 411979697Snon struct scsi_low_softc *slp; 412067468Snon{ 412179697Snon struct targ_info *ti = slp->sl_Tnexus; 412267468Snon 412379697Snon /* only I -> T, invalid! */ 412479697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 412567468Snon return 0; 412667468Snon} 412767468Snon 412867468Snonstatic int 412979697Snonscsi_low_msginfunc_msg_reject(slp) 413079697Snon struct scsi_low_softc *slp; 413167468Snon{ 413279697Snon struct targ_info *ti = slp->sl_Tnexus; 413367468Snon struct scsi_low_msgout_data *mdp; 413467468Snon u_int msgflags; 413567468Snon 413679697Snon if (ti->ti_emsgflags != 0) 413767468Snon { 413879697Snon printf("%s: msg flags [0x%x] rejected\n", 413979697Snon slp->sl_xname, ti->ti_emsgflags); 414067468Snon msgflags = SCSI_LOW_MSG_REJECT; 414167468Snon mdp = &scsi_low_msgout_data[0]; 414267468Snon for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) 414367468Snon { 414467468Snon if ((ti->ti_emsgflags & mdp->md_flags) != 0) 414567468Snon { 414667468Snon ti->ti_emsgflags &= ~mdp->md_flags; 414767468Snon if (mdp->md_errfunc != NULL) 414879697Snon (*mdp->md_errfunc) (slp, msgflags); 414967468Snon break; 415067468Snon } 415167468Snon } 415279697Snon return 0; 415367468Snon } 415479697Snon else 415579697Snon { 415679697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: rejected msg not found"); 415779697Snon slp->sl_error |= MSGERR; 415879697Snon } 415979697Snon return EINVAL; 416067468Snon} 416167468Snon 416279697Snonint 416367468Snonscsi_low_msgin(slp, ti, c) 416467468Snon struct scsi_low_softc *slp; 416567468Snon struct targ_info *ti; 416679697Snon u_int c; 416767468Snon{ 416867468Snon struct scsi_low_msgin_data *sdp; 416967468Snon struct lun_info *li; 417067468Snon u_int8_t msg; 417167468Snon 417279697Snon#ifdef SCSI_LOW_DIAGNOSTIC 417379697Snon if (ti != slp->sl_Tnexus) 417479697Snon { 417579697Snon scsi_low_print(slp, NULL); 417679697Snon panic("scsi_low_msgin: Target nexus inconsistent"); 417779697Snon } 417879697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 417979697Snon 418067468Snon /* 418167468Snon * Phase changes, clear the pointer. 418267468Snon */ 418367468Snon if (ti->ti_ophase != ti->ti_phase) 418467468Snon { 418567468Snon MSGINPTR_CLR(ti); 418679697Snon ti->ti_msgin_parity_error = 0; 418779697Snon 418879697Snon slp->sl_ph_count ++; 418979697Snon if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES) 419079697Snon { 419179697Snon printf("%s: too many phase changes\n", slp->sl_xname); 419279697Snon slp->sl_error |= FATALIO; 419379697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 419479697Snon } 419567468Snon } 419667468Snon 419767468Snon /* 419867468Snon * Store a current messages byte into buffer and 419967468Snon * wait for the completion of the current msg. 420067468Snon */ 420179697Snon ti->ti_msgin[ti->ti_msginptr ++] = (u_int8_t) c; 420267468Snon if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN) 420367468Snon { 420467468Snon ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1; 420567468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 420667468Snon } 420767468Snon 420867468Snon /* 420979697Snon * Check parity errors. 421079697Snon */ 421179697Snon if ((c & SCSI_LOW_DATA_PE) != 0) 421279697Snon { 421379697Snon ti->ti_msgin_parity_error ++; 421479697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0); 421579697Snon goto out; 421679697Snon } 421779697Snon 421879697Snon if (ti->ti_msgin_parity_error != 0) 421979697Snon goto out; 422079697Snon 422179697Snon /* 422267468Snon * Calculate messages length. 422367468Snon */ 422467468Snon msg = ti->ti_msgin[0]; 422567468Snon if (msg < MSGIN_DATA_LAST) 422667468Snon sdp = &scsi_low_msgin_data[msg]; 422767468Snon else 422867468Snon sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST]; 422967468Snon 423067468Snon if (ti->ti_msginlen == 0) 423167468Snon { 423267468Snon ti->ti_msginlen = sdp->md_len; 423367468Snon } 423467468Snon 423567468Snon /* 423667468Snon * Check comletion. 423767468Snon */ 423867468Snon if (ti->ti_msginptr < ti->ti_msginlen) 423979697Snon return EJUSTRETURN; 424067468Snon 424167468Snon /* 424267468Snon * Do process. 424367468Snon */ 424467468Snon if ((msg & MSG_IDENTIFY) == 0) 424567468Snon { 424679697Snon if (((*sdp->md_msgfunc) (slp)) == EJUSTRETURN) 424779697Snon return EJUSTRETURN; 424867468Snon } 424967468Snon else 425067468Snon { 425179697Snon li = slp->sl_Lnexus; 425267468Snon if (li == NULL) 425367468Snon { 425479697Snon li = scsi_low_alloc_li(ti, MSGCMD_LUN(msg), 0); 425567468Snon if (li == NULL) 425667468Snon goto badlun; 425779697Snon slp->sl_Lnexus = li; 425879697Snon (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp); 425967468Snon } 426079697Snon else 426179697Snon { 426279697Snon if (MSGCMD_LUN(msg) != li->li_lun) 426379697Snon goto badlun; 426479697Snon } 426567468Snon 426679697Snon if (slp->sl_Qnexus == NULL && li->li_nqio == 0) 426767468Snon { 426867468Snon if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG)) 426979697Snon { 427079697Snon#ifdef SCSI_LOW_DEBUG 427179697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0) 427279697Snon { 427379697Snon goto out; 427479697Snon } 427579697Snon#endif /* SCSI_LOW_DEBUG */ 427667468Snon goto badlun; 427779697Snon } 427867468Snon } 427967468Snon } 428079697Snon goto out; 428167468Snon 428267468Snon /* 428379697Snon * Msg process completed, reset msgin pointer and assert ATN if desired. 428467468Snon */ 428579697Snonbadlun: 428679697Snon slp->sl_error |= FATALIO; 428779697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 428879697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: identify wrong"); 428979697Snon 429079697Snonout: 429179697Snon if (ti->ti_msginptr < ti->ti_msginlen) 429279697Snon return EJUSTRETURN; 429379697Snon 429479697Snon#ifdef SCSI_LOW_DIAGNOSTIC 429579697Snon scsi_low_msg_log_write(&ti->ti_log_msgin, 429679697Snon &ti->ti_msgin[0], ti->ti_msginlen); 429779697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 429879697Snon 429979697Snon MSGINPTR_CLR(ti); 430079697Snon return 0; 430179697Snon} 430279697Snon 430379697Snon/********************************************************** 430479697Snon * disconnect 430579697Snon **********************************************************/ 430679697Snonint 430779697Snonscsi_low_disconnected(slp, ti) 430879697Snon struct scsi_low_softc *slp; 430979697Snon struct targ_info *ti; 431079697Snon{ 431179697Snon struct slccb *cb = slp->sl_Qnexus; 431279697Snon 431379697Snon /* check phase completion */ 431479697Snon switch (slp->sl_msgphase) 431567468Snon { 431679697Snon case MSGPH_RESET: 431779697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 431879697Snon scsi_low_msginfunc_cc(slp); 431979697Snon scsi_low_reset_nexus_target(slp, slp->sl_Tnexus, 0); 432079697Snon goto io_resume; 432167468Snon 432279697Snon case MSGPH_ABORT: 432379697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 432479697Snon scsi_low_msginfunc_cc(slp); 432579697Snon scsi_low_reset_nexus_lun(slp, slp->sl_Lnexus, 0); 432679697Snon goto io_resume; 432779697Snon 432879697Snon case MSGPH_TERM: 432979697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 433079697Snon scsi_low_msginfunc_cc(slp); 433179697Snon goto io_resume; 433279697Snon 433379697Snon case MSGPH_DISC: 433479697Snon if (cb != NULL) 433567468Snon { 433679697Snon struct lun_info *li; 433779697Snon 433879697Snon li = cb->li; 433979697Snon TAILQ_INSERT_TAIL(&li->li_discq, cb, ccb_chain); 434079697Snon cb->ccb_flags |= CCB_DISCQ; 434179697Snon cb->ccb_error |= slp->sl_error; 434279697Snon li->li_disc ++; 434379697Snon ti->ti_disc ++; 434479697Snon slp->sl_disc ++; 434579697Snon } 434679697Snon 434779697Snon#ifdef SCSI_LOW_STATICS 434879697Snon scsi_low_statics.nexus_disconnected ++; 434979697Snon#endif /* SCSI_LOW_STATICS */ 435079697Snon 435179697Snon#ifdef SCSI_LOW_DEBUG 435279697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DISC, ti->ti_id) != 0) 435379697Snon { 435479697Snon printf("## SCSI_LOW_DISCONNECTED ===============\n"); 435579697Snon scsi_low_print(slp, NULL); 435679697Snon } 435779697Snon#endif /* SCSI_LOW_DEBUG */ 435879697Snon break; 435979697Snon 436079697Snon case MSGPH_NULL: 436179697Snon slp->sl_error |= FATALIO; 436279697Snon if (ti->ti_phase == PH_SELSTART) 436379697Snon slp->sl_error |= SELTIMEOUTIO; 436479697Snon else 436579697Snon slp->sl_error |= UBFERR; 436679697Snon /* fall through */ 436779697Snon 436879697Snon case MSGPH_LCTERM: 436979697Snon case MSGPH_CMDC: 437079697Snonio_resume: 437179697Snon if (cb == NULL) 437279697Snon break; 437379697Snon 437479697Snon#ifdef SCSI_LOW_DEBUG 437579697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id)) 437679697Snon { 437779697Snon if (cb->ccb_omsgoutflag == SCSI_LOW_MSG_NOOP && 437879697Snon (cb->ccb_msgoutflag != 0 || 437979697Snon (ti->ti_msgflags & SCSI_LOW_MSG_NOOP))) 438079697Snon { 438179697Snon scsi_low_info(slp, ti, "ATTEN CHECK FAILED"); 438279697Snon } 438379697Snon } 438479697Snon#endif /* SCSI_LOW_DEBUG */ 438579697Snon 438679697Snon cb->ccb_error |= slp->sl_error; 438779697Snon if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY) 438879697Snon { 438979697Snon cb->ccb_flags |= CCB_STARTQ; 439079697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 439179697Snon } 439279697Snon break; 439379697Snon } 439479697Snon 439579697Snon scsi_low_bus_release(slp, ti); 439679697Snon scsi_low_start(slp); 439779697Snon return 1; 439879697Snon} 439979697Snon 440079697Snon/********************************************************** 440179697Snon * TAG operations 440279697Snon **********************************************************/ 4403104094Sphkstatic int 440479697Snonscsi_low_alloc_qtag(cb) 440579697Snon struct slccb *cb; 440679697Snon{ 440779697Snon struct lun_info *li = cb->li; 440879697Snon scsi_low_tag_t etag; 440979697Snon 441079697Snon if (cb->ccb_otag != SCSI_LOW_UNKTAG) 441179697Snon return 0; 441279697Snon 441379697Snon#ifndef SCSI_LOW_ALT_QTAG_ALLOCATE 441479697Snon etag = ffs(li->li_qtagbits); 441579697Snon if (etag == 0) 441679697Snon return ENOSPC; 441779697Snon 441879697Snon li->li_qtagbits &= ~(1 << (etag - 1)); 441979697Snon cb->ccb_otag = etag; 442079697Snon return 0; 442179697Snon 442279697Snon#else /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 442379697Snon for (etag = li->li_qd ; li->li_qd < SCSI_LOW_MAXNEXUS; li->li_qd ++) 442479697Snon if (li->li_qtagarray[li->li_qd] == 0) 442579697Snon goto found; 442679697Snon 442779697Snon for (li->li_qd = 0; li->li_qd < etag; li->li_qd ++) 442879697Snon if (li->li_qtagarray[li->li_qd] == 0) 442979697Snon goto found; 443079697Snon 443179697Snon return ENOSPC; 443279697Snon 443379697Snonfound: 443479697Snon li->li_qtagarray[li->li_qd] ++; 443579697Snon cb->ccb_otag = (li->li_qd ++); 443679697Snon return 0; 443779697Snon#endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 443879697Snon} 443979697Snon 4440104094Sphkstatic int 444179697Snonscsi_low_dealloc_qtag(cb) 444279697Snon struct slccb *cb; 444379697Snon{ 444479697Snon struct lun_info *li = cb->li; 444579697Snon scsi_low_tag_t etag; 444679697Snon 444779697Snon if (cb->ccb_otag == SCSI_LOW_UNKTAG) 444879697Snon return 0; 444979697Snon 445079697Snon#ifndef SCSI_LOW_ALT_QTAG_ALLOCATE 445179697Snon etag = cb->ccb_otag - 1; 445267468Snon#ifdef SCSI_LOW_DIAGNOSTIC 445379697Snon if (etag >= sizeof(li->li_qtagbits) * NBBY) 445479697Snon panic("scsi_low_dealloc_tag: illegal tag"); 445567468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 445679697Snon li->li_qtagbits |= (1 << etag); 445779697Snon 445879697Snon#else /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 445979697Snon etag = cb->ccb_otag; 446079697Snon#ifdef SCSI_LOW_DIAGNOSTIC 446179697Snon if (etag >= SCSI_LOW_MAXNEXUS) 446279697Snon panic("scsi_low_dealloc_tag: illegal tag"); 446379697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 446479697Snon li->li_qtagarray[etag] --; 446579697Snon#endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 446679697Snon 446779697Snon cb->ccb_otag = SCSI_LOW_UNKTAG; 446879697Snon return 0; 446979697Snon} 447079697Snon 4471104094Sphkstatic struct slccb * 447279697Snonscsi_low_revoke_ccb(slp, cb, fdone) 447379697Snon struct scsi_low_softc *slp; 447479697Snon struct slccb *cb; 447579697Snon int fdone; 447679697Snon{ 447779697Snon struct targ_info *ti = cb->ti; 447879697Snon struct lun_info *li = cb->li; 447979697Snon 448079697Snon#ifdef SCSI_LOW_DIAGNOSTIC 448179697Snon if ((cb->ccb_flags & (CCB_STARTQ | CCB_DISCQ)) == 448279697Snon (CCB_STARTQ | CCB_DISCQ)) 448379697Snon { 4484106890Simp panic("%s: ccb in both queue", slp->sl_xname); 448567468Snon } 448679697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 448767468Snon 448879697Snon if ((cb->ccb_flags & CCB_STARTQ) != 0) 448979697Snon { 449079697Snon TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); 449179697Snon } 449279697Snon 449379697Snon if ((cb->ccb_flags & CCB_DISCQ) != 0) 449479697Snon { 449579697Snon TAILQ_REMOVE(&li->li_discq, cb, ccb_chain); 449679697Snon li->li_disc --; 449779697Snon ti->ti_disc --; 449879697Snon slp->sl_disc --; 449979697Snon } 450079697Snon 450179697Snon cb->ccb_flags &= ~(CCB_STARTQ | CCB_DISCQ | 450279697Snon CCB_SENSE | CCB_CLEARQ | CCB_INTERNAL); 450379697Snon 450479697Snon if (fdone != 0 && 450579697Snon (cb->ccb_rcnt ++ >= slp->sl_max_retry || 450679697Snon (cb->ccb_flags & CCB_NORETRY) != 0)) 450779697Snon { 450879697Snon cb->ccb_error |= FATALIO; 450979697Snon cb->ccb_flags &= ~CCB_AUTOSENSE; 451079697Snon if (scsi_low_done(slp, cb) != SCSI_LOW_DONE_COMPLETE) 4511106890Simp panic("%s: done ccb retried", slp->sl_xname); 451279697Snon return NULL; 451379697Snon } 451479697Snon else 451579697Snon { 451679697Snon cb->ccb_error |= PENDINGIO; 451779697Snon scsi_low_deactivate_qtag(cb); 451879697Snon scsi_low_ccb_message_retry(cb); 451979697Snon cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 452079697Snon return cb; 452179697Snon } 452267468Snon} 452367468Snon 4524104094Sphkstatic void 452579697Snonscsi_low_reset_nexus_lun(slp, li, fdone) 452679697Snon struct scsi_low_softc *slp; 452779697Snon struct lun_info *li; 452879697Snon int fdone; 452979697Snon{ 453079697Snon struct slccb *cb, *ncb, *ecb; 453179697Snon 453279697Snon if (li == NULL) 453379697Snon return; 453479697Snon 453579697Snon ecb = NULL; 453679697Snon for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = ncb) 453779697Snon { 453879697Snon ncb = TAILQ_NEXT(cb, ccb_chain); 453979697Snon cb = scsi_low_revoke_ccb(slp, cb, fdone); 454079697Snon if (cb != NULL) 454179697Snon { 454279697Snon /* 454379697Snon * presumely keep ordering of io 454479697Snon */ 454579697Snon cb->ccb_flags |= CCB_STARTQ; 454679697Snon if (ecb == NULL) 454779697Snon { 454879697Snon TAILQ_INSERT_HEAD(&slp->sl_start,\ 454979697Snon cb, ccb_chain); 455079697Snon } 455179697Snon else 455279697Snon { 455379697Snon TAILQ_INSERT_AFTER(&slp->sl_start,\ 455479697Snon ecb, cb, ccb_chain); 455579697Snon } 455679697Snon ecb = cb; 455779697Snon } 455879697Snon } 455979697Snon} 456079697Snon 456167468Snon/************************************************************** 456267468Snon * Qurik setup 456367468Snon **************************************************************/ 456467468Snonstatic void 456579697Snonscsi_low_calcf_lun(li) 456667468Snon struct lun_info *li; 456767468Snon{ 456879697Snon struct targ_info *ti = li->li_ti; 456967468Snon struct scsi_low_softc *slp = ti->ti_sc; 457079697Snon u_int cfgflags, diskflags; 457167468Snon 457279697Snon if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID) 457379697Snon cfgflags = li->li_cfgflags; 457479697Snon else 457579697Snon cfgflags = 0; 457679697Snon 457779697Snon diskflags = li->li_diskflags & li->li_quirks; 457879697Snon 457979697Snon /* disconnect */ 458067468Snon li->li_flags &= ~SCSI_LOW_DISC; 458167468Snon if ((slp->sl_cfgflags & CFG_NODISC) == 0 && 458279697Snon (diskflags & SCSI_LOW_DISK_DISC) != 0 && 458379697Snon (cfgflags & SCSI_LOW_DISC) != 0) 458467468Snon li->li_flags |= SCSI_LOW_DISC; 458567468Snon 458679697Snon /* parity */ 458767468Snon li->li_flags |= SCSI_LOW_NOPARITY; 458867468Snon if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 && 458979697Snon (diskflags & SCSI_LOW_DISK_PARITY) != 0 && 459079697Snon (cfgflags & SCSI_LOW_NOPARITY) == 0) 459167468Snon li->li_flags &= ~SCSI_LOW_NOPARITY; 459267468Snon 459379697Snon /* qtag */ 459479697Snon if ((slp->sl_cfgflags & CFG_NOQTAG) == 0 && 459579697Snon (cfgflags & SCSI_LOW_QTAG) != 0 && 459679697Snon (diskflags & SCSI_LOW_DISK_QTAG) != 0) 459779697Snon { 459879697Snon li->li_flags |= SCSI_LOW_QTAG; 459979697Snon li->li_maxnexus = SCSI_LOW_MAXNEXUS; 460079697Snon li->li_maxnqio = li->li_maxnexus; 460179697Snon } 460279697Snon else 460379697Snon { 460479697Snon li->li_flags &= ~SCSI_LOW_QTAG; 460579697Snon li->li_maxnexus = 0; 460679697Snon li->li_maxnqio = li->li_maxnexus; 460779697Snon } 460879697Snon 460979697Snon /* cmd link */ 461079697Snon li->li_flags &= ~SCSI_LOW_LINK; 461179697Snon if ((cfgflags & SCSI_LOW_LINK) != 0 && 461279697Snon (diskflags & SCSI_LOW_DISK_LINK) != 0) 461379697Snon li->li_flags |= SCSI_LOW_LINK; 461479697Snon 461579697Snon /* compatible flags */ 461667468Snon li->li_flags &= ~SCSI_LOW_SYNC; 461779697Snon if (ti->ti_maxsynch.offset > 0) 461879697Snon li->li_flags |= SCSI_LOW_SYNC; 461979697Snon 462079697Snon#ifdef SCSI_LOW_DEBUG 462179697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0) 462267468Snon { 462379697Snon scsi_low_calcf_show(li); 462467468Snon } 462579697Snon#endif /* SCSI_LOW_DEBUG */ 462679697Snon} 462779697Snon 462879697Snonstatic void 462979697Snonscsi_low_calcf_target(ti) 463079697Snon struct targ_info *ti; 463179697Snon{ 463279697Snon struct scsi_low_softc *slp = ti->ti_sc; 463379697Snon u_int offset, period, diskflags; 463479697Snon 463579697Snon diskflags = ti->ti_diskflags & ti->ti_quirks; 463679697Snon 463779697Snon /* synch */ 463879697Snon if ((slp->sl_cfgflags & CFG_ASYNC) == 0 && 463979697Snon (diskflags & SCSI_LOW_DISK_SYNC) != 0) 464079697Snon { 464179697Snon offset = ti->ti_maxsynch.offset; 464279697Snon period = ti->ti_maxsynch.period; 464379697Snon if (offset == 0 || period == 0) 464479697Snon offset = period = 0; 464579697Snon } 464667468Snon else 464779697Snon { 464879697Snon offset = period = 0; 464979697Snon } 465067468Snon 465179697Snon ti->ti_maxsynch.offset = offset; 465279697Snon ti->ti_maxsynch.period = period; 465379697Snon 465479697Snon /* wide */ 465579697Snon if ((diskflags & SCSI_LOW_DISK_WIDE_32) == 0 && 465679697Snon ti->ti_width > SCSI_LOW_BUS_WIDTH_16) 465779697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_16; 465879697Snon 465979697Snon if ((diskflags & SCSI_LOW_DISK_WIDE_16) == 0 && 466079697Snon ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 466179697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_8; 466279697Snon 466379697Snon if (ti->ti_flags_valid == SCSI_LOW_TARG_FLAGS_ALL_VALID) 466467468Snon { 466579697Snon if (ti->ti_maxsynch.offset != ti->ti_osynch.offset || 466679697Snon ti->ti_maxsynch.period != ti->ti_osynch.period) 466779697Snon ti->ti_setup_msg |= SCSI_LOW_MSG_SYNCH; 466879697Snon if (ti->ti_width != ti->ti_owidth) 466979697Snon ti->ti_setup_msg |= (SCSI_LOW_MSG_WIDE | SCSI_LOW_MSG_SYNCH); 467079697Snon 467179697Snon ti->ti_osynch = ti->ti_maxsynch; 467279697Snon ti->ti_owidth = ti->ti_width; 467367468Snon } 467467468Snon 467579697Snon#ifdef SCSI_LOW_DEBUG 467679697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0) 467779697Snon { 467879697Snon printf("%s(%d:*): max period(%dns) offset(%d) width(%d)\n", 467979697Snon slp->sl_xname, ti->ti_id, 468079697Snon ti->ti_maxsynch.period * 4, 468179697Snon ti->ti_maxsynch.offset, 468279697Snon ti->ti_width); 468379697Snon } 468479697Snon#endif /* SCSI_LOW_DEBUG */ 468567468Snon} 468667468Snon 468779697Snonstatic void 468879697Snonscsi_low_calcf_show(li) 468979697Snon struct lun_info *li; 469079697Snon{ 469179697Snon struct targ_info *ti = li->li_ti; 469279697Snon struct scsi_low_softc *slp = ti->ti_sc; 469379697Snon 469479697Snon printf("%s(%d:%d): period(%d ns) offset(%d) width(%d) flags 0x%b\n", 469579697Snon slp->sl_xname, ti->ti_id, li->li_lun, 469679697Snon ti->ti_maxsynch.period * 4, 469779697Snon ti->ti_maxsynch.offset, 469879697Snon ti->ti_width, 469979697Snon li->li_flags, SCSI_LOW_BITS); 470079697Snon} 470179697Snon 470279697Snon#ifdef SCSI_LOW_START_UP_CHECK 470379697Snon/************************************************************** 470479697Snon * scsi world start up 470579697Snon **************************************************************/ 470692770Salfredstatic int scsi_low_poll(struct scsi_low_softc *, struct slccb *); 470779697Snon 470867468Snonstatic int 470979697Snonscsi_low_start_up(slp) 471079697Snon struct scsi_low_softc *slp; 471167468Snon{ 471267468Snon struct targ_info *ti; 471367468Snon struct lun_info *li; 471479697Snon struct slccb *cb; 471579697Snon int target, lun; 471667468Snon 471779697Snon printf("%s: scsi_low: probing all devices ....\n", slp->sl_xname); 471867468Snon 471979697Snon for (target = 0; target < slp->sl_ntargs; target ++) 472079697Snon { 472179697Snon if (target == slp->sl_hostid) 472279697Snon { 472379697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 472479697Snon { 472579697Snon printf("%s: scsi_low: target %d (host card)\n", 472679697Snon slp->sl_xname, target); 472779697Snon } 472879697Snon continue; 472979697Snon } 473067468Snon 473179697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 473279697Snon { 473379697Snon printf("%s: scsi_low: target %d lun ", 473479697Snon slp->sl_xname, target); 473579697Snon } 473667468Snon 473779697Snon ti = slp->sl_ti[target]; 473879697Snon for (lun = 0; lun < slp->sl_nluns; lun ++) 473979697Snon { 474079697Snon if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL) 474179697Snon break; 474279697Snon 474379697Snon cb->osdep = NULL; 474479697Snon cb->bp = NULL; 474579697Snon 474679697Snon li = scsi_low_alloc_li(ti, lun, 1); 474779697Snon 474879697Snon scsi_low_enqueue(slp, ti, li, cb, 474979697Snon CCB_AUTOSENSE | CCB_POLLED, 0); 475079697Snon 475179697Snon scsi_low_poll(slp, cb); 475279697Snon 475379697Snon if (li->li_state != SCSI_LOW_LUN_OK) 475479697Snon break; 475579697Snon 475679697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 475779697Snon { 475879697Snon printf("%d ", lun); 475979697Snon } 476079697Snon } 476179697Snon 476279697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 476379697Snon { 476479697Snon printf("\n"); 476579697Snon } 476679697Snon } 476767468Snon return 0; 476867468Snon} 476967468Snon 477079697Snonstatic int 477179697Snonscsi_low_poll(slp, cb) 477279697Snon struct scsi_low_softc *slp; 477379697Snon struct slccb *cb; 477479697Snon{ 477579697Snon int tcount; 477679697Snon 477779697Snon tcount = 0; 477879697Snon while (slp->sl_nio > 0) 477979697Snon { 478079697Snon SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_POLL_HZ); 478179697Snon 478279697Snon (*slp->sl_funcs->scsi_low_poll) (slp); 478379697Snon if (tcount ++ < SCSI_LOW_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) 478479697Snon continue; 478579697Snon 478679697Snon tcount = 0; 478779697Snon scsi_low_timeout_check(slp); 478879697Snon } 478979697Snon 479079697Snon return 0; 479179697Snon} 479279697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 479379697Snon 479467468Snon/********************************************************** 479567468Snon * DEBUG SECTION 479667468Snon **********************************************************/ 479779697Snon#ifdef SCSI_LOW_DEBUG 479867468Snonstatic void 479979697Snonscsi_low_test_abort(slp, ti, li) 480079697Snon struct scsi_low_softc *slp; 480179697Snon struct targ_info *ti; 480279697Snon struct lun_info *li; 480379697Snon{ 480479697Snon struct slccb *acb; 480579697Snon 480679697Snon if (li->li_disc > 1) 480779697Snon { 480879697Snon acb = TAILQ_FIRST(&li->li_discq); 480979697Snon if (scsi_low_abort_ccb(slp, acb) == 0) 481079697Snon { 481179697Snon printf("%s: aborting ccb(0x%lx) start\n", 481279697Snon slp->sl_xname, (u_long) acb); 481379697Snon } 481479697Snon } 481579697Snon} 481679697Snon 481779697Snonstatic void 481879697Snonscsi_low_test_atten(slp, ti, msg) 481979697Snon struct scsi_low_softc *slp; 482079697Snon struct targ_info *ti; 482179697Snon u_int msg; 482279697Snon{ 482379697Snon 482479697Snon if (slp->sl_ph_count < SCSI_LOW_MAX_ATTEN_CHECK) 482579697Snon scsi_low_assert_msg(slp, ti, msg, 0); 482679697Snon else 482779697Snon printf("%s: atten check OK\n", slp->sl_xname); 482879697Snon} 482979697Snon 483079697Snonstatic void 483179697Snonscsi_low_test_cmdlnk(slp, cb) 483279697Snon struct scsi_low_softc *slp; 483379697Snon struct slccb *cb; 483479697Snon{ 483579697Snon#define SCSI_LOW_CMDLNK_NOK (CCB_INTERNAL | CCB_SENSE | CCB_CLEARQ) 483679697Snon 483779697Snon if ((cb->ccb_flags & SCSI_LOW_CMDLNK_NOK) != 0) 483879697Snon return; 483979697Snon 484079697Snon memcpy(cb->ccb_scsi_cmd, slp->sl_scp.scp_cmd, 484179697Snon slp->sl_scp.scp_cmdlen); 484279697Snon cb->ccb_scsi_cmd[slp->sl_scp.scp_cmdlen - 1] |= 1; 484379697Snon slp->sl_scp.scp_cmd = cb->ccb_scsi_cmd; 484479697Snon} 484579697Snon#endif /* SCSI_LOW_DEBUG */ 484679697Snon 484779697Snon/* static */ void 484867468Snonscsi_low_info(slp, ti, s) 484967468Snon struct scsi_low_softc *slp; 485067468Snon struct targ_info *ti; 485167468Snon u_char *s; 485267468Snon{ 485367468Snon 485479697Snon if (slp == NULL) 485579697Snon slp = LIST_FIRST(&sl_tab); 485679697Snon if (s == NULL) 485779697Snon s = "no message"; 485879697Snon 485979697Snon printf(">>>>> SCSI_LOW_INFO(0x%lx): %s\n", (u_long) slp->sl_Tnexus, s); 486067468Snon if (ti == NULL) 486167468Snon { 486279697Snon for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 486379697Snon ti = TAILQ_NEXT(ti, ti_chain)) 486479697Snon { 486567468Snon scsi_low_print(slp, ti); 486679697Snon } 486767468Snon } 486867468Snon else 486979697Snon { 487067468Snon scsi_low_print(slp, ti); 487179697Snon } 487267468Snon} 487367468Snon 487467468Snonstatic u_char *phase[] = 487567468Snon{ 487667468Snon "FREE", "ARBSTART", "SELSTART", "SELECTED", 487767468Snon "CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL" 487867468Snon}; 487967468Snon 488067468Snonvoid 488167468Snonscsi_low_print(slp, ti) 488267468Snon struct scsi_low_softc *slp; 488367468Snon struct targ_info *ti; 488467468Snon{ 488579697Snon struct lun_info *li; 488679697Snon struct slccb *cb; 488779697Snon struct sc_p *sp; 488867468Snon 488979697Snon if (ti == NULL || ti == slp->sl_Tnexus) 489079697Snon { 489179697Snon ti = slp->sl_Tnexus; 489279697Snon li = slp->sl_Lnexus; 489379697Snon cb = slp->sl_Qnexus; 489479697Snon } 489579697Snon else 489679697Snon { 489779697Snon li = LIST_FIRST(&ti->ti_litab); 489879697Snon cb = TAILQ_FIRST(&li->li_discq); 489979697Snon } 490079697Snon sp = &slp->sl_scp; 490167468Snon 490279697Snon printf("%s: === NEXUS T(0x%lx) L(0x%lx) Q(0x%lx) NIO(%d) ===\n", 490379697Snon slp->sl_xname, (u_long) ti, (u_long) li, (u_long) cb, 490479697Snon slp->sl_nio); 490567468Snon 490667468Snon /* target stat */ 490767468Snon if (ti != NULL) 490867468Snon { 490979697Snon u_int flags = 0, maxnqio = 0, nqio = 0; 491067468Snon int lun = -1; 491167468Snon 491267468Snon if (li != NULL) 491367468Snon { 491467468Snon lun = li->li_lun; 491567468Snon flags = li->li_flags; 491679697Snon maxnqio = li->li_maxnqio; 491779697Snon nqio = li->li_nqio; 491867468Snon } 491967468Snon 492079697Snon printf("%s(%d:%d) ph<%s> => ph<%s> DISC(%d) QIO(%d:%d)\n", 492179697Snon slp->sl_xname, 492267468Snon ti->ti_id, lun, phase[(int) ti->ti_ophase], 492379697Snon phase[(int) ti->ti_phase], ti->ti_disc, 492479697Snon nqio, maxnqio); 492567468Snon 492679697Snon if (cb != NULL) 492779697Snon { 492879697Snonprintf("CCB: cmd[0] 0x%x clen 0x%x dlen 0x%x<0x%x stat 0x%x err %b\n", 492979697Snon (u_int) cb->ccb_scp.scp_cmd[0], 493079697Snon cb->ccb_scp.scp_cmdlen, 493179697Snon cb->ccb_datalen, 493279697Snon cb->ccb_scp.scp_datalen, 493379697Snon (u_int) cb->ccb_sscp.scp_status, 493479697Snon cb->ccb_error, SCSI_LOW_ERRORBITS); 493579697Snon } 493667468Snon 493779697Snonprintf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] attention: %d\n", 493879697Snon (u_int) (ti->ti_msginptr), 493979697Snon (u_int) (ti->ti_msgin[0]), 494079697Snon (u_int) (ti->ti_msgin[1]), 494179697Snon (u_int) (ti->ti_msgin[2]), 494279697Snon (u_int) (ti->ti_msgin[3]), 494379697Snon (u_int) (ti->ti_msgin[4]), 494479697Snon slp->sl_atten); 494579697Snon 494667468Snonprintf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n", 494779697Snon (u_int) ti->ti_msgflags, 494879697Snon (u_int) (ti->ti_msgoutstr[0]), 494979697Snon (u_int) (ti->ti_msgoutstr[1]), 495079697Snon (u_int) (ti->ti_msgoutstr[2]), 495179697Snon (u_int) (ti->ti_msgoutstr[3]), 495279697Snon (u_int) (ti->ti_msgoutstr[4]), 495379697Snon ti->ti_msgoutlen, 495479697Snon flags, SCSI_LOW_BITS); 495567468Snon 495679697Snon#ifdef SCSI_LOW_DIAGNOSTIC 495779697Snon scsi_low_msg_log_show(&ti->ti_log_msgin, "MIN LOG ", 2); 495879697Snon scsi_low_msg_log_show(&ti->ti_log_msgout, "MOUT LOG", 2); 495979697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 496067468Snon 496167468Snon } 496279697Snon 496379697Snon printf("SCB: daddr 0x%lx dlen 0x%x stat 0x%x err %b\n", 496479697Snon (u_long) sp->scp_data, 496579697Snon sp->scp_datalen, 496679697Snon (u_int) sp->scp_status, 496779697Snon slp->sl_error, SCSI_LOW_ERRORBITS); 496867468Snon} 4969