scsi_low.c revision 92770
167468Snon/* $FreeBSD: head/sys/cam/scsi/scsi_low.c 92770 2002-03-20 08:56:31Z alfred $ */ 279697Snon/* $NecBSD: scsi_low.c,v 1.24.10.8 2001/06/26 07:39:44 honda Exp $ */ 367468Snon/* $NetBSD$ */ 467468Snon 567468Snon#define SCSI_LOW_STATICS 679697Snon#define SCSI_LOW_DEBUG 779697Snon#define SCSI_LOW_NEGOTIATE_BEFORE_SENSE 879697Snon#define SCSI_LOW_START_UP_CHECK 979697Snon 1079697Snon/* #define SCSI_LOW_INFO_DETAIL */ 1179697Snon/* #define SCSI_LOW_QCLEAR_AFTER_CA */ 1279697Snon/* #define SCSI_LOW_FLAGS_QUIRKS_OK */ 1379697Snon 1467468Snon#ifdef __NetBSD__ 1567468Snon#define SCSI_LOW_TARGET_OPEN 1679697Snon#endif /* __NetBSD__ */ 1767468Snon 1879697Snon#ifdef __FreeBSD__ 1979697Snon#define SCSI_LOW_FLAGS_QUIRKS_OK 2079697Snon#endif /* __FreeBSD__ */ 2179697Snon 2267468Snon/* 2367468Snon * [NetBSD for NEC PC-98 series] 2479697Snon * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 2567468Snon * NetBSD/pc98 porting staff. All rights reserved. 2679697Snon * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001 2767468Snon * Naofumi HONDA. All rights reserved. 2879697Snon * 2979697Snon * [Ported for FreeBSD CAM] 3079697Snon * Copyright (c) 2000, 2001 3179697Snon * MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro. 3279697Snon * All rights reserved. 3367468Snon * 3467468Snon * Redistribution and use in source and binary forms, with or without 3567468Snon * modification, are permitted provided that the following conditions 3667468Snon * are met: 3767468Snon * 1. Redistributions of source code must retain the above copyright 3867468Snon * notice, this list of conditions and the following disclaimer. 3967468Snon * 2. Redistributions in binary form must reproduce the above copyright 4067468Snon * notice, this list of conditions and the following disclaimer in the 4167468Snon * documentation and/or other materials provided with the distribution. 4267468Snon * 3. The name of the author may not be used to endorse or promote products 4367468Snon * derived from this software without specific prior written permission. 4467468Snon * 4567468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4667468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 4767468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 4867468Snon * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 4967468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 5067468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 5167468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5267468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 5367468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 5467468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 5567468Snon * POSSIBILITY OF SUCH DAMAGE. 5667468Snon */ 5767468Snon 5867468Snon/* <On the nexus establishment> 5967468Snon * When our host is reselected, 6067468Snon * nexus establish processes are little complicated. 6167468Snon * Normal steps are followings: 6279697Snon * 1) Our host selected by target => target nexus (slp->sl_Tnexus) 6379697Snon * 2) Identify msgin => lun nexus (slp->sl_Lnexus) 6479697Snon * 3) Qtag msg => ccb nexus (slp->sl_Qnexus) 6567468Snon */ 6667468Snon#include "opt_ddb.h" 6767468Snon 6867468Snon#include <sys/param.h> 6967468Snon#include <sys/systm.h> 7067468Snon#include <sys/kernel.h> 7179697Snon 7273025Snon#ifdef __FreeBSD__ 7373025Snon#if __FreeBSD_version >= 500001 7467468Snon#include <sys/bio.h> 7579697Snon#else 7679697Snon#include <machine/clock.h> 7773025Snon#endif 7869979Snon#include <sys/devicestat.h> 7979697Snon#endif /* __FreeBSD__ */ 8079697Snon 8167468Snon#include <sys/buf.h> 8267468Snon#include <sys/queue.h> 8367468Snon#include <sys/malloc.h> 8467468Snon#include <sys/errno.h> 8567468Snon 8679697Snon#ifdef __NetBSD__ 8779697Snon#include <sys/device.h> 8867468Snon#include <vm/vm.h> 8967468Snon 9067468Snon#include <machine/bus.h> 9167468Snon#include <machine/intr.h> 9267468Snon#include <machine/dvcfg.h> 9367468Snon 9467468Snon#include <dev/cons.h> 9567468Snon 9667468Snon#include <dev/scsipi/scsipi_all.h> 9767468Snon#include <dev/scsipi/scsipiconf.h> 9867468Snon#include <dev/scsipi/scsipi_disk.h> 9967468Snon#include <dev/scsipi/scsi_all.h> 10067468Snon#include <dev/scsipi/scsiconf.h> 10179697Snon#include <sys/scsiio.h> 10267468Snon 10367468Snon#include <i386/Cbus/dev/scsi_low.h> 10479697Snon#endif /* __NetBSD__ */ 10579697Snon 10667468Snon#ifdef __FreeBSD__ 10767468Snon#include <cam/cam.h> 10867468Snon#include <cam/cam_ccb.h> 10967468Snon#include <cam/cam_sim.h> 11067468Snon#include <cam/cam_debug.h> 11167468Snon#include <cam/cam_periph.h> 11267468Snon 11367468Snon#include <cam/scsi/scsi_all.h> 11473025Snon#include <cam/scsi/scsi_message.h> 11567468Snon 11667468Snon#include <cam/scsi/scsi_low.h> 11767468Snon 11867468Snon#include <sys/cons.h> 11979697Snon#endif /* __FreeBSD__ */ 12067468Snon 12179697Snon/************************************************************** 12279697Snon * Constants 12379697Snon **************************************************************/ 12479697Snon#define SCSI_LOW_POLL_HZ 1000 12567468Snon 12679697Snon/* functions return values */ 12779697Snon#define SCSI_LOW_START_NO_QTAG 0 12879697Snon#define SCSI_LOW_START_QTAG 1 12979697Snon 13067468Snon#define SCSI_LOW_DONE_COMPLETE 0 13167468Snon#define SCSI_LOW_DONE_RETRY 1 13267468Snon 13379697Snon/* internal disk flags */ 13479697Snon#define SCSI_LOW_DISK_DISC 0x00000001 13579697Snon#define SCSI_LOW_DISK_QTAG 0x00000002 13679697Snon#define SCSI_LOW_DISK_LINK 0x00000004 13779697Snon#define SCSI_LOW_DISK_PARITY 0x00000008 13879697Snon#define SCSI_LOW_DISK_SYNC 0x00010000 13979697Snon#define SCSI_LOW_DISK_WIDE_16 0x00020000 14079697Snon#define SCSI_LOW_DISK_WIDE_32 0x00040000 14179697Snon#define SCSI_LOW_DISK_WIDE (SCSI_LOW_DISK_WIDE_16 | SCSI_LOW_DISK_WIDE_32) 14279697Snon#define SCSI_LOW_DISK_LFLAGS 0x0000ffff 14379697Snon#define SCSI_LOW_DISK_TFLAGS 0xffff0000 14479697Snon 14579697Snon/************************************************************** 14679697Snon * Declarations 14779697Snon **************************************************************/ 14892770Salfred/* static */ void scsi_low_info(struct scsi_low_softc *, struct targ_info *, u_char *); 14992770Salfredstatic void scsi_low_engage(void *); 15092770Salfredstatic struct slccb *scsi_low_establish_ccb(struct targ_info *, struct lun_info *, scsi_low_tag_t); 15192770Salfredstatic int scsi_low_done(struct scsi_low_softc *, struct slccb *); 15292770Salfredstatic int scsi_low_setup_done(struct scsi_low_softc *, struct slccb *); 15392770Salfredstatic void scsi_low_bus_release(struct scsi_low_softc *, struct targ_info *); 15492770Salfredstatic void scsi_low_twiddle_wait(void); 15592770Salfredstatic struct lun_info *scsi_low_alloc_li(struct targ_info *, int, int); 15692770Salfredstatic struct targ_info *scsi_low_alloc_ti(struct scsi_low_softc *, int); 15792770Salfredstatic void scsi_low_calcf_lun(struct lun_info *); 15892770Salfredstatic void scsi_low_calcf_target(struct targ_info *); 15992770Salfredstatic void scsi_low_calcf_show(struct lun_info *); 16092770Salfredstatic void scsi_low_reset_nexus(struct scsi_low_softc *, int); 16192770Salfredstatic void scsi_low_reset_nexus_target(struct scsi_low_softc *, struct targ_info *, int); 16292770Salfredstatic void scsi_low_reset_nexus_lun(struct scsi_low_softc *, struct lun_info *, int); 16392770Salfredstatic int scsi_low_init(struct scsi_low_softc *, u_int); 16492770Salfredstatic void scsi_low_start(struct scsi_low_softc *); 16592770Salfredstatic void scsi_low_free_ti(struct scsi_low_softc *); 16667468Snon 16792770Salfredstatic int scsi_low_alloc_qtag(struct slccb *); 16892770Salfredstatic int scsi_low_dealloc_qtag(struct slccb *); 16992770Salfredstatic int scsi_low_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *, u_int, u_int); 17092770Salfredstatic int scsi_low_message_enqueue(struct scsi_low_softc *, struct targ_info *, struct lun_info *, u_int); 17192770Salfredstatic void scsi_low_unit_ready_cmd(struct slccb *); 17292770Salfredstatic void scsi_low_timeout(void *); 17392770Salfredstatic int scsi_low_timeout_check(struct scsi_low_softc *); 17479697Snon#ifdef SCSI_LOW_START_UP_CHECK 17592770Salfredstatic int scsi_low_start_up(struct scsi_low_softc *); 17679697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 17792770Salfredstatic int scsi_low_abort_ccb(struct scsi_low_softc *, struct slccb *); 17892770Salfredstatic struct slccb *scsi_low_revoke_ccb(struct scsi_low_softc *, struct slccb *, int); 17979697Snon 18079697Snonint scsi_low_version_major = 2; 18179697Snonint scsi_low_version_minor = 17; 18279697Snon 18379697Snonstatic struct scsi_low_softc_tab sl_tab = LIST_HEAD_INITIALIZER(sl_tab); 18479697Snon 18579697Snon/************************************************************** 18679697Snon * Debug, Run test and Statics 18779697Snon **************************************************************/ 18879697Snon#ifdef SCSI_LOW_INFO_DETAIL 18979697Snon#define SCSI_LOW_INFO(slp, ti, s) scsi_low_info((slp), (ti), (s)) 19079697Snon#else /* !SCSI_LOW_INFO_DETAIL */ 19179697Snon#define SCSI_LOW_INFO(slp, ti, s) printf("%s: %s\n", (slp)->sl_xname, (s)) 19279697Snon#endif /* !SCSI_LOW_INFO_DETAIL */ 19379697Snon 19467468Snon#ifdef SCSI_LOW_STATICS 19589113Smsmithstatic struct scsi_low_statics { 19667468Snon int nexus_win; 19767468Snon int nexus_fail; 19867468Snon int nexus_disconnected; 19967468Snon int nexus_reselected; 20067468Snon int nexus_conflict; 20167468Snon} scsi_low_statics; 20267468Snon#endif /* SCSI_LOW_STATICS */ 20379697Snon 20479697Snon#ifdef SCSI_LOW_DEBUG 20579697Snon#define SCSI_LOW_DEBUG_DONE 0x00001 20679697Snon#define SCSI_LOW_DEBUG_DISC 0x00002 20779697Snon#define SCSI_LOW_DEBUG_SENSE 0x00004 20879697Snon#define SCSI_LOW_DEBUG_CALCF 0x00008 20979697Snon#define SCSI_LOW_DEBUG_ACTION 0x10000 21079697Snonint scsi_low_debug = 0; 21179697Snon 21279697Snon#define SCSI_LOW_MAX_ATTEN_CHECK 32 21379697Snon#define SCSI_LOW_ATTEN_CHECK 0x0001 21479697Snon#define SCSI_LOW_CMDLNK_CHECK 0x0002 21579697Snon#define SCSI_LOW_ABORT_CHECK 0x0004 21679697Snon#define SCSI_LOW_NEXUS_CHECK 0x0008 21779697Snonint scsi_low_test = 0; 21879697Snonint scsi_low_test_id = 0; 21979697Snon 22092770Salfredstatic void scsi_low_test_abort(struct scsi_low_softc *, struct targ_info *, struct lun_info *); 22192770Salfredstatic void scsi_low_test_cmdlnk(struct scsi_low_softc *, struct slccb *); 22292770Salfredstatic void scsi_low_test_atten(struct scsi_low_softc *, struct targ_info *, u_int); 22379697Snon#define SCSI_LOW_DEBUG_TEST_GO(fl, id) \ 22479697Snon ((scsi_low_test & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0) 22579697Snon#define SCSI_LOW_DEBUG_GO(fl, id) \ 22679697Snon ((scsi_low_debug & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0) 22779697Snon#endif /* SCSI_LOW_DEBUG */ 22879697Snon 22967468Snon/************************************************************** 23079697Snon * CCB 23179697Snon **************************************************************/ 23279697SnonGENERIC_CCB_STATIC_ALLOC(scsi_low, slccb) 23379697SnonGENERIC_CCB(scsi_low, slccb, ccb_chain) 23479697Snon 23579697Snon/************************************************************** 23679697Snon * Inline functions 23779697Snon **************************************************************/ 23879697Snon#define SCSI_LOW_INLINE static __inline 23992770SalfredSCSI_LOW_INLINE void scsi_low_activate_qtag(struct slccb *); 24092770SalfredSCSI_LOW_INLINE void scsi_low_deactivate_qtag(struct slccb *); 24192770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_assert(struct slccb *, u_int); 24292770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_exec(struct scsi_low_softc *, struct slccb *); 24392770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_retry(struct slccb *); 24492770SalfredSCSI_LOW_INLINE void scsi_low_ccb_message_clear(struct slccb *); 24592770SalfredSCSI_LOW_INLINE void scsi_low_init_msgsys(struct scsi_low_softc *, struct targ_info *); 24679697Snon 24779697SnonSCSI_LOW_INLINE void 24879697Snonscsi_low_activate_qtag(cb) 24979697Snon struct slccb *cb; 25079697Snon{ 25179697Snon struct lun_info *li = cb->li; 25279697Snon 25379697Snon if (cb->ccb_tag != SCSI_LOW_UNKTAG) 25479697Snon return; 25579697Snon 25679697Snon li->li_nqio ++; 25779697Snon cb->ccb_tag = cb->ccb_otag; 25879697Snon} 25979697Snon 26079697SnonSCSI_LOW_INLINE void 26179697Snonscsi_low_deactivate_qtag(cb) 26279697Snon struct slccb *cb; 26379697Snon{ 26479697Snon struct lun_info *li = cb->li; 26579697Snon 26679697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 26779697Snon return; 26879697Snon 26979697Snon li->li_nqio --; 27079697Snon cb->ccb_tag = SCSI_LOW_UNKTAG; 27179697Snon} 27279697Snon 27379697SnonSCSI_LOW_INLINE void 27479697Snonscsi_low_ccb_message_exec(slp, cb) 27579697Snon struct scsi_low_softc *slp; 27679697Snon struct slccb *cb; 27779697Snon{ 27879697Snon 27979697Snon scsi_low_assert_msg(slp, cb->ti, cb->ccb_msgoutflag, 0); 28079697Snon cb->ccb_msgoutflag = 0; 28179697Snon} 28279697Snon 28379697SnonSCSI_LOW_INLINE void 28479697Snonscsi_low_ccb_message_assert(cb, msg) 28579697Snon struct slccb *cb; 28679697Snon u_int msg; 28779697Snon{ 28879697Snon 28979697Snon cb->ccb_msgoutflag = cb->ccb_omsgoutflag = msg; 29079697Snon} 29179697Snon 29279697SnonSCSI_LOW_INLINE void 29379697Snonscsi_low_ccb_message_retry(cb) 29479697Snon struct slccb *cb; 29579697Snon{ 29679697Snon cb->ccb_msgoutflag = cb->ccb_omsgoutflag; 29779697Snon} 29879697Snon 29979697SnonSCSI_LOW_INLINE void 30079697Snonscsi_low_ccb_message_clear(cb) 30179697Snon struct slccb *cb; 30279697Snon{ 30379697Snon cb->ccb_msgoutflag = 0; 30479697Snon} 30579697Snon 30679697SnonSCSI_LOW_INLINE void 30779697Snonscsi_low_init_msgsys(slp, ti) 30879697Snon struct scsi_low_softc *slp; 30979697Snon struct targ_info *ti; 31079697Snon{ 31179697Snon 31279697Snon ti->ti_msginptr = 0; 31379697Snon ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0; 31479697Snon SCSI_LOW_DEASSERT_ATN(slp); 31579697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL); 31679697Snon} 31779697Snon 31879697Snon/*============================================================= 31979697Snon * START OF OS switch (All OS depend fucntions should be here) 32079697Snon =============================================================*/ 32179697Snon/* common os depend utitlities */ 32279697Snon#define SCSI_LOW_CMD_RESIDUAL_CHK 0x0001 32379697Snon#define SCSI_LOW_CMD_ORDERED_QTAG 0x0002 32479697Snon#define SCSI_LOW_CMD_ABORT_WARNING 0x0004 32579697Snon 32679697Snonstatic u_int8_t scsi_low_cmd_flags[256] = { 32779697Snon/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ 32879697Snon/*0*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0, 32979697Snon/*1*/ 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 33079697Snon/*2*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 5, 5, 33179697Snon/*3*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 33279697Snon}; 33379697Snon 33479697Snonstruct scsi_low_error_code { 33579697Snon int error_bits; 33679697Snon int error_code; 33779697Snon}; 33879697Snon 33992770Salfredstatic struct slccb *scsi_low_find_ccb(struct scsi_low_softc *, u_int, u_int, void *); 34092770Salfredstatic int scsi_low_translate_error_code(struct slccb *, struct scsi_low_error_code *); 34179697Snon 34279697Snonstatic struct slccb * 34379697Snonscsi_low_find_ccb(slp, target, lun, osdep) 34479697Snon struct scsi_low_softc *slp; 34579697Snon u_int target, lun; 34679697Snon void *osdep; 34779697Snon{ 34879697Snon struct targ_info *ti; 34979697Snon struct lun_info *li; 35079697Snon struct slccb *cb; 35179697Snon 35279697Snon ti = slp->sl_ti[target]; 35379697Snon li = scsi_low_alloc_li(ti, lun, 0); 35479697Snon if (li == NULL) 35579697Snon return NULL; 35679697Snon 35779697Snon if ((cb = slp->sl_Qnexus) != NULL && cb->osdep == osdep) 35879697Snon return cb; 35979697Snon 36079697Snon for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL; 36179697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 36279697Snon { 36379697Snon if (cb->osdep == osdep) 36479697Snon return cb; 36579697Snon } 36679697Snon 36779697Snon for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; 36879697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 36979697Snon { 37079697Snon if (cb->osdep == osdep) 37179697Snon return cb; 37279697Snon } 37379697Snon return NULL; 37479697Snon} 37579697Snon 37679697Snonstatic int 37779697Snonscsi_low_translate_error_code(cb, tp) 37879697Snon struct slccb *cb; 37979697Snon struct scsi_low_error_code *tp; 38079697Snon{ 38179697Snon 38279697Snon if (cb->ccb_error == 0) 38379697Snon return tp->error_code; 38479697Snon 38579697Snon for (tp ++; (cb->ccb_error & tp->error_bits) == 0; tp ++) 38679697Snon ; 38779697Snon return tp->error_code; 38879697Snon} 38979697Snon 39079697Snon#ifdef SCSI_LOW_INTERFACE_XS 39179697Snon/************************************************************** 39279697Snon * SCSI INTERFACE (XS) 39379697Snon **************************************************************/ 39479697Snon#define SCSI_LOW_MINPHYS 0x10000 39579697Snon#define SCSI_LOW_MALLOC(size) malloc((size), M_DEVBUF, M_NOWAIT) 39679697Snon#define SCSI_LOW_FREE(pt) free((pt), M_DEVBUF) 39779697Snon#define SCSI_LOW_ALLOC_CCB(flags) scsi_low_get_ccb((flags)) 39879697Snon#define SCSI_LOW_XS_POLL_HZ 1000 39979697Snon 40092770Salfredstatic int scsi_low_poll_xs(struct scsi_low_softc *, struct slccb *); 40192770Salfredstatic void scsi_low_scsi_minphys_xs(struct buf *); 40279697Snon#ifdef SCSI_LOW_TARGET_OPEN 40392770Salfredstatic int scsi_low_target_open(struct scsipi_link *, struct cfdata *); 40479697Snon#endif /* SCSI_LOW_TARGET_OPEN */ 40592770Salfredstatic int scsi_low_scsi_cmd_xs(struct scsipi_xfer *); 40692770Salfredstatic int scsi_low_enable_xs(void *, int); 40792770Salfredstatic int scsi_low_ioctl_xs(struct scsipi_link *, u_long, caddr_t, int, struct proc *); 40879697Snon 40992770Salfredstatic int scsi_low_attach_xs(struct scsi_low_softc *); 41092770Salfredstatic int scsi_low_world_start_xs(struct scsi_low_softc *); 41192770Salfredstatic int scsi_low_dettach_xs(struct scsi_low_softc *); 41292770Salfredstatic int scsi_low_ccb_setup_xs(struct scsi_low_softc *, struct slccb *); 41392770Salfredstatic int scsi_low_done_xs(struct scsi_low_softc *, struct slccb *); 41492770Salfredstatic void scsi_low_timeout_xs(struct scsi_low_softc *, int, int); 41592770Salfredstatic u_int scsi_low_translate_quirks_xs(u_int); 41692770Salfredstatic void scsi_low_setup_quirks_xs(struct targ_info *, struct lun_info *, u_int); 41779697Snon 41879697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_xs = { 41979697Snon scsi_low_attach_xs, 42079697Snon scsi_low_world_start_xs, 42179697Snon scsi_low_dettach_xs, 42279697Snon scsi_low_ccb_setup_xs, 42379697Snon scsi_low_done_xs, 42479697Snon scsi_low_timeout_xs 42579697Snon}; 42679697Snon 42779697Snonstruct scsipi_device scsi_low_dev = { 42879697Snon NULL, /* Use default error handler */ 42979697Snon NULL, /* have a queue, served by this */ 43079697Snon NULL, /* have no async handler */ 43179697Snon NULL, /* Use default 'done' routine */ 43279697Snon}; 43379697Snon 43479697Snonstruct scsi_low_error_code scsi_low_error_code_xs[] = { 43579697Snon {0, XS_NOERROR}, 43679697Snon {SENSEIO, XS_SENSE}, 43779697Snon {BUSYERR, XS_BUSY }, 43879697Snon {SELTIMEOUTIO, XS_SELTIMEOUT}, 43979697Snon {TIMEOUTIO, XS_TIMEOUT}, 44079697Snon {-1, XS_DRIVER_STUFFUP} 44179697Snon}; 44279697Snon 44379697Snonstatic int 44479697Snonscsi_low_ioctl_xs(link, cmd, addr, flag, p) 44579697Snon struct scsipi_link *link; 44679697Snon u_long cmd; 44779697Snon caddr_t addr; 44879697Snon int flag; 44979697Snon struct proc *p; 45079697Snon{ 45179697Snon struct scsi_low_softc *slp; 45279697Snon int s, error = ENOTTY; 45379697Snon 45479697Snon slp = (struct scsi_low_softc *) link->adapter_softc; 45579697Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 45679697Snon return ENXIO; 45779697Snon 45879697Snon if (cmd == SCBUSIORESET) 45979697Snon { 46079697Snon s = SCSI_LOW_SPLSCSI(); 46179697Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL); 46279697Snon splx(s); 46379697Snon error = 0; 46479697Snon } 46579697Snon else if (slp->sl_funcs->scsi_low_ioctl != 0) 46679697Snon { 46779697Snon error = (*slp->sl_funcs->scsi_low_ioctl) 46879697Snon (slp, cmd, addr, flag, p); 46979697Snon } 47079697Snon 47179697Snon return error; 47279697Snon} 47379697Snon 47479697Snonstatic int 47579697Snonscsi_low_enable_xs(arg, enable) 47679697Snon void *arg; 47779697Snon int enable; 47879697Snon{ 47979697Snon struct scsi_low_softc *slp = arg; 48079697Snon 48179697Snon if (enable != 0) 48279697Snon { 48379697Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 48479697Snon return ENXIO; 48579697Snon } 48679697Snon else 48779697Snon { 48879697Snon if ((slp->sl_flags & HW_INACTIVE) != 0 || 48979697Snon (slp->sl_flags & HW_POWERCTRL) == 0) 49079697Snon return 0; 49179697Snon 49279697Snon slp->sl_flags |= HW_POWDOWN; 49379697Snon if (slp->sl_funcs->scsi_low_power != NULL) 49479697Snon { 49579697Snon (*slp->sl_funcs->scsi_low_power) 49679697Snon (slp, SCSI_LOW_POWDOWN); 49779697Snon } 49879697Snon } 49979697Snon return 0; 50079697Snon} 50179697Snon 50279697Snonstatic void 50379697Snonscsi_low_scsi_minphys_xs(bp) 50479697Snon struct buf *bp; 50579697Snon{ 50679697Snon 50779697Snon if (bp->b_bcount > SCSI_LOW_MINPHYS) 50879697Snon bp->b_bcount = SCSI_LOW_MINPHYS; 50979697Snon minphys(bp); 51079697Snon} 51179697Snon 51279697Snonstatic int 51379697Snonscsi_low_poll_xs(slp, cb) 51479697Snon struct scsi_low_softc *slp; 51579697Snon struct slccb *cb; 51679697Snon{ 51779697Snon struct scsipi_xfer *xs = cb->osdep; 51879697Snon int tcount; 51979697Snon 52079697Snon cb->ccb_flags |= CCB_NOSDONE; 52179697Snon tcount = 0; 52279697Snon 52379697Snon while (slp->sl_nio > 0) 52479697Snon { 52579697Snon SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_XS_POLL_HZ); 52679697Snon 52779697Snon (*slp->sl_funcs->scsi_low_poll) (slp); 52879697Snon 52979697Snon if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0) 53079697Snon { 53179697Snon cb->ccb_flags |= CCB_NORETRY; 53279697Snon cb->ccb_error |= FATALIO; 53379697Snon (void) scsi_low_revoke_ccb(slp, cb, 1); 53479697Snon printf("%s: hardware inactive in poll mode\n", 53579697Snon slp->sl_xname); 53679697Snon } 53779697Snon 53879697Snon if ((xs->flags & ITSDONE) != 0) 53979697Snon break; 54079697Snon 54179697Snon if (tcount ++ < SCSI_LOW_XS_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) 54279697Snon continue; 54379697Snon 54479697Snon tcount = 0; 54579697Snon scsi_low_timeout_check(slp); 54679697Snon } 54779697Snon 54879697Snon xs->flags |= ITSDONE; 54979697Snon scsipi_done(xs); 55079697Snon return COMPLETE; 55179697Snon} 55279697Snon 55379697Snonstatic int 55479697Snonscsi_low_scsi_cmd_xs(xs) 55579697Snon struct scsipi_xfer *xs; 55679697Snon{ 55779697Snon struct scsipi_link *splp = xs->sc_link; 55879697Snon struct scsi_low_softc *slp = splp->adapter_softc; 55979697Snon struct targ_info *ti; 56079697Snon struct lun_info *li; 56179697Snon struct slccb *cb; 56279697Snon int s, targ, lun, flags, rv; 56379697Snon 56479697Snon if ((cb = SCSI_LOW_ALLOC_CCB(xs->flags & SCSI_NOSLEEP)) == NULL) 56579697Snon return TRY_AGAIN_LATER; 56679697Snon 56779697Snon targ = splp->scsipi_scsi.target, 56879697Snon lun = splp->scsipi_scsi.lun; 56979697Snon ti = slp->sl_ti[targ]; 57079697Snon 57179697Snon cb->osdep = xs; 57279697Snon cb->bp = xs->bp; 57379697Snon 57479697Snon if ((xs->flags & SCSI_POLL) == 0) 57579697Snon flags = CCB_AUTOSENSE; 57679697Snon else 57779697Snon flags = CCB_AUTOSENSE | CCB_POLLED; 57879697Snon 57979697Snon 58079697Snon s = SCSI_LOW_SPLSCSI(); 58179697Snon li = scsi_low_alloc_li(ti, lun, 1); 58279697Snon if ((u_int) splp->quirks != li->li_sloi.sloi_quirks) 58379697Snon { 58479697Snon scsi_low_setup_quirks_xs(ti, li, (u_int) splp->quirks); 58579697Snon } 58679697Snon 58779697Snon if ((xs->flags & SCSI_RESET) != 0) 58879697Snon { 58979697Snon flags |= CCB_NORETRY | CCB_URGENT; 59079697Snon scsi_low_enqueue(slp, ti, li, cb, flags, SCSI_LOW_MSG_RESET); 59179697Snon } 59279697Snon else 59379697Snon { 59479697Snon if (ti->ti_setup_msg != 0) 59579697Snon { 59679697Snon scsi_low_message_enqueue(slp, ti, li, flags); 59779697Snon } 59879697Snon 59979697Snon flags |= CCB_SCSIIO; 60079697Snon scsi_low_enqueue(slp, ti, li, cb, flags, 0); 60179697Snon } 60279697Snon 60379697Snon#ifdef SCSI_LOW_DEBUG 60479697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, ti->ti_id) != 0) 60579697Snon { 60679697Snon scsi_low_test_abort(slp, ti, li); 60779697Snon } 60879697Snon#endif /* SCSI_LOW_DEBUG */ 60979697Snon 61079697Snon if ((cb->ccb_flags & CCB_POLLED) != 0) 61179697Snon { 61279697Snon rv = scsi_low_poll_xs(slp, cb); 61379697Snon } 61479697Snon else 61579697Snon { 61679697Snon rv = SUCCESSFULLY_QUEUED; 61779697Snon } 61879697Snon splx(s); 61979697Snon return rv; 62079697Snon} 62179697Snon 62279697Snonstatic int 62379697Snonscsi_low_attach_xs(slp) 62479697Snon struct scsi_low_softc *slp; 62579697Snon{ 62679697Snon struct scsipi_adapter *sap; 62779697Snon struct scsipi_link *splp; 62879697Snon 62979697Snon strncpy(slp->sl_xname, slp->sl_dev.dv_xname, 16); 63079697Snon 63179697Snon sap = SCSI_LOW_MALLOC(sizeof(*sap)); 63279697Snon if (sap == NULL) 63379697Snon return ENOMEM; 63479697Snon splp = SCSI_LOW_MALLOC(sizeof(*splp)); 63579697Snon if (splp == NULL) 63679697Snon return ENOMEM; 63779697Snon 63879697Snon SCSI_LOW_BZERO(sap, sizeof(*sap)); 63979697Snon SCSI_LOW_BZERO(splp, sizeof(*splp)); 64079697Snon 64179697Snon sap->scsipi_cmd = scsi_low_scsi_cmd_xs; 64279697Snon sap->scsipi_minphys = scsi_low_scsi_minphys_xs; 64379697Snon sap->scsipi_enable = scsi_low_enable_xs; 64479697Snon sap->scsipi_ioctl = scsi_low_ioctl_xs; 64579697Snon#ifdef SCSI_LOW_TARGET_OPEN 64679697Snon sap->open_target_lu = scsi_low_target_open; 64779697Snon#endif /* SCSI_LOW_TARGET_OPEN */ 64879697Snon 64979697Snon splp->adapter_softc = slp; 65079697Snon splp->scsipi_scsi.adapter_target = slp->sl_hostid; 65179697Snon splp->scsipi_scsi.max_target = slp->sl_ntargs - 1; 65279697Snon splp->scsipi_scsi.max_lun = slp->sl_nluns - 1; 65379697Snon splp->scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE; 65479697Snon splp->openings = slp->sl_openings; 65579697Snon splp->type = BUS_SCSI; 65679697Snon splp->adapter_softc = slp; 65779697Snon splp->adapter = sap; 65879697Snon splp->device = &scsi_low_dev; 65979697Snon 66079697Snon slp->sl_si.si_splp = splp; 66179697Snon slp->sl_show_result = SHOW_ALL_NEG; 66279697Snon return 0; 66379697Snon} 66479697Snon 66579697Snonstatic int 66679697Snonscsi_low_world_start_xs(slp) 66779697Snon struct scsi_low_softc *slp; 66879697Snon{ 66979697Snon 67079697Snon return 0; 67179697Snon} 67279697Snon 67379697Snonstatic int 67479697Snonscsi_low_dettach_xs(slp) 67579697Snon struct scsi_low_softc *slp; 67679697Snon{ 67779697Snon 67879697Snon /* 67979697Snon * scsipi does not have dettach bus fucntion. 68079697Snon * 68179697Snon scsipi_dettach_scsibus(slp->sl_si.si_splp); 68279697Snon */ 68379697Snon return 0; 68479697Snon} 68579697Snon 68679697Snonstatic int 68779697Snonscsi_low_ccb_setup_xs(slp, cb) 68879697Snon struct scsi_low_softc *slp; 68979697Snon struct slccb *cb; 69079697Snon{ 69179697Snon struct scsipi_xfer *xs = (struct scsipi_xfer *) cb->osdep; 69279697Snon 69379697Snon if ((cb->ccb_flags & CCB_SCSIIO) != 0) 69479697Snon { 69579697Snon cb->ccb_scp.scp_cmd = (u_int8_t *) xs->cmd; 69679697Snon cb->ccb_scp.scp_cmdlen = xs->cmdlen; 69779697Snon cb->ccb_scp.scp_data = xs->data; 69879697Snon cb->ccb_scp.scp_datalen = xs->datalen; 69979697Snon cb->ccb_scp.scp_direction = (xs->flags & SCSI_DATA_OUT) ? 70079697Snon SCSI_LOW_WRITE : SCSI_LOW_READ; 70179697Snon cb->ccb_tcmax = xs->timeout / 1000; 70279697Snon } 70379697Snon else 70479697Snon { 70579697Snon scsi_low_unit_ready_cmd(cb); 70679697Snon } 70779697Snon return SCSI_LOW_START_QTAG; 70879697Snon} 70979697Snon 71079697Snonstatic int 71179697Snonscsi_low_done_xs(slp, cb) 71279697Snon struct scsi_low_softc *slp; 71379697Snon struct slccb *cb; 71479697Snon{ 71579697Snon struct scsipi_xfer *xs; 71679697Snon 71779697Snon xs = (struct scsipi_xfer *) cb->osdep; 71879697Snon if (cb->ccb_error == 0) 71979697Snon { 72079697Snon xs->error = XS_NOERROR; 72179697Snon xs->resid = 0; 72279697Snon } 72379697Snon else 72479697Snon { 72579697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 72679697Snon cb->ccb_error |= ABORTIO; 72779697Snon 72879697Snon if ((cb->ccb_flags & CCB_NORETRY) == 0 && 72979697Snon (cb->ccb_error & ABORTIO) == 0) 73079697Snon return EJUSTRETURN; 73179697Snon 73279697Snon if ((cb->ccb_error & SENSEIO) != 0) 73379697Snon { 73479697Snon xs->sense.scsi_sense = cb->ccb_sense; 73579697Snon } 73679697Snon 73779697Snon xs->error = scsi_low_translate_error_code(cb, 73879697Snon &scsi_low_error_code_xs[0]); 73979697Snon 74079697Snon#ifdef SCSI_LOW_DIAGNOSTIC 74179697Snon if ((cb->ccb_flags & CCB_SILENT) == 0 && 74279697Snon cb->ccb_scp.scp_cmdlen > 0 && 74379697Snon (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 74479697Snon SCSI_LOW_CMD_ABORT_WARNING) != 0) 74579697Snon { 74679697Snon printf("%s: WARNING: scsi_low IO abort\n", 74779697Snon slp->sl_xname); 74879697Snon scsi_low_print(slp, NULL); 74979697Snon } 75079697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 75179697Snon } 75279697Snon 75379697Snon if (cb->ccb_scp.scp_status == ST_UNKNOWN) 75479697Snon xs->status = 0; /* XXX */ 75579697Snon else 75679697Snon xs->status = cb->ccb_scp.scp_status; 75779697Snon 75879697Snon xs->flags |= ITSDONE; 75979697Snon if ((cb->ccb_flags & CCB_NOSDONE) == 0) 76079697Snon scsipi_done(xs); 76179697Snon 76279697Snon return 0; 76379697Snon} 76479697Snon 76579697Snonstatic void 76679697Snonscsi_low_timeout_xs(slp, ch, action) 76779697Snon struct scsi_low_softc *slp; 76879697Snon int ch; 76979697Snon int action; 77079697Snon{ 77179697Snon 77279697Snon switch (ch) 77379697Snon { 77479697Snon case SCSI_LOW_TIMEOUT_CH_IO: 77579697Snon switch (action) 77679697Snon { 77779697Snon case SCSI_LOW_TIMEOUT_START: 77879697Snon timeout(scsi_low_timeout, slp, 77979697Snon hz / SCSI_LOW_TIMEOUT_HZ); 78079697Snon break; 78179697Snon case SCSI_LOW_TIMEOUT_STOP: 78279697Snon untimeout(scsi_low_timeout, slp); 78379697Snon break; 78479697Snon } 78579697Snon break; 78679697Snon 78779697Snon case SCSI_LOW_TIMEOUT_CH_ENGAGE: 78879697Snon switch (action) 78979697Snon { 79079697Snon case SCSI_LOW_TIMEOUT_START: 79179697Snon timeout(scsi_low_engage, slp, 1); 79279697Snon break; 79379697Snon case SCSI_LOW_TIMEOUT_STOP: 79479697Snon untimeout(scsi_low_engage, slp); 79579697Snon break; 79679697Snon } 79779697Snon break; 79879697Snon 79979697Snon case SCSI_LOW_TIMEOUT_CH_RECOVER: 80079697Snon break; 80179697Snon } 80279697Snon} 80379697Snon 80479697Snonu_int 80579697Snonscsi_low_translate_quirks_xs(quirks) 80679697Snon u_int quirks; 80779697Snon{ 80879697Snon u_int flags; 80979697Snon 81079697Snon flags = SCSI_LOW_DISK_LFLAGS | SCSI_LOW_DISK_TFLAGS; 81179697Snon 81279697Snon#ifdef SDEV_NODISC 81379697Snon if (quirks & SDEV_NODISC) 81479697Snon flags &= ~SCSI_LOW_DISK_DISC; 81579697Snon#endif /* SDEV_NODISC */ 81679697Snon#ifdef SDEV_NOPARITY 81779697Snon if (quirks & SDEV_NOPARITY) 81879697Snon flags &= ~SCSI_LOW_DISK_PARITY; 81979697Snon#endif /* SDEV_NOPARITY */ 82079697Snon#ifdef SDEV_NOCMDLNK 82179697Snon if (quirks & SDEV_NOCMDLNK) 82279697Snon flags &= ~SCSI_LOW_DISK_LINK; 82379697Snon#endif /* SDEV_NOCMDLNK */ 82479697Snon#ifdef SDEV_NOTAG 82579697Snon if (quirks & SDEV_NOTAG) 82679697Snon flags &= ~SCSI_LOW_DISK_QTAG; 82779697Snon#endif /* SDEV_NOTAG */ 82879697Snon#ifdef SDEV_NOSYNC 82979697Snon if (quirks & SDEV_NOSYNC) 83079697Snon flags &= ~SCSI_LOW_DISK_SYNC; 83179697Snon#endif /* SDEV_NOSYNC */ 83279697Snon 83379697Snon return flags; 83479697Snon} 83579697Snon 83679697Snonstatic void 83779697Snonscsi_low_setup_quirks_xs(ti, li, flags) 83879697Snon struct targ_info *ti; 83979697Snon struct lun_info *li; 84079697Snon u_int flags; 84179697Snon{ 84279697Snon u_int quirks; 84379697Snon 84479697Snon li->li_sloi.sloi_quirks = flags; 84579697Snon quirks = scsi_low_translate_quirks_xs(flags); 84679697Snon ti->ti_quirks = quirks & SCSI_LOW_DISK_TFLAGS; 84779697Snon li->li_quirks = quirks & SCSI_LOW_DISK_LFLAGS; 84879697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 84979697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 85079697Snon scsi_low_calcf_target(ti); 85179697Snon scsi_low_calcf_lun(li); 85279697Snon scsi_low_calcf_show(li); 85379697Snon} 85479697Snon 85579697Snon#ifdef SCSI_LOW_TARGET_OPEN 85679697Snonstatic int 85779697Snonscsi_low_target_open(link, cf) 85879697Snon struct scsipi_link *link; 85979697Snon struct cfdata *cf; 86079697Snon{ 86179697Snon u_int target = link->scsipi_scsi.target; 86279697Snon u_int lun = link->scsipi_scsi.lun; 86379697Snon struct scsi_low_softc *slp; 86479697Snon struct targ_info *ti; 86579697Snon struct lun_info *li; 86679697Snon 86779697Snon slp = (struct scsi_low_softc *) link->adapter_softc; 86879697Snon ti = slp->sl_ti[target]; 86979697Snon li = scsi_low_alloc_li(ti, lun, 0); 87079697Snon if (li == NULL) 87179697Snon return 0; 87279697Snon 87379697Snon li->li_cfgflags = cf->cf_flags; 87479697Snon scsi_low_setup_quirks_xs(ti, li, (u_int) link->quirks); 87579697Snon return 0; 87679697Snon} 87779697Snon#endif /* SCSI_LOW_TARGET_OPEN */ 87879697Snon 87979697Snon#endif /* SCSI_LOW_INTERFACE_XS */ 88079697Snon 88179697Snon#ifdef SCSI_LOW_INTERFACE_CAM 88279697Snon/************************************************************** 88379697Snon * SCSI INTERFACE (CAM) 88479697Snon **************************************************************/ 88579697Snon#define SCSI_LOW_MALLOC(size) malloc((size), M_DEVBUF, M_NOWAIT) 88679697Snon#define SCSI_LOW_FREE(pt) free((pt), M_DEVBUF) 88779697Snon#define SCSI_LOW_ALLOC_CCB(flags) scsi_low_get_ccb() 88879697Snon 88992770Salfredstatic void scsi_low_poll_cam(struct cam_sim *); 89092770Salfredstatic void scsi_low_cam_rescan_callback(struct cam_periph *, union ccb *); 89192770Salfredstatic void scsi_low_rescan_bus_cam(struct scsi_low_softc *); 89292770Salfredvoid scsi_low_scsi_action_cam(struct cam_sim *, union ccb *); 89379697Snon 89492770Salfredstatic int scsi_low_attach_cam(struct scsi_low_softc *); 89592770Salfredstatic int scsi_low_world_start_cam(struct scsi_low_softc *); 89692770Salfredstatic int scsi_low_dettach_cam(struct scsi_low_softc *); 89792770Salfredstatic int scsi_low_ccb_setup_cam(struct scsi_low_softc *, struct slccb *); 89892770Salfredstatic int scsi_low_done_cam(struct scsi_low_softc *, struct slccb *); 89992770Salfredstatic void scsi_low_timeout_cam(struct scsi_low_softc *, int, int); 90079697Snon 90179697Snonstruct scsi_low_osdep_funcs scsi_low_osdep_funcs_cam = { 90279697Snon scsi_low_attach_cam, 90379697Snon scsi_low_world_start_cam, 90479697Snon scsi_low_dettach_cam, 90579697Snon scsi_low_ccb_setup_cam, 90679697Snon scsi_low_done_cam, 90779697Snon scsi_low_timeout_cam 90879697Snon}; 90979697Snon 91079697Snonstruct scsi_low_error_code scsi_low_error_code_cam[] = { 91179697Snon {0, CAM_REQ_CMP}, 91279697Snon {SENSEIO, CAM_AUTOSNS_VALID | CAM_REQ_CMP_ERR}, 91379697Snon {SENSEERR, CAM_AUTOSENSE_FAIL}, 91479697Snon {UACAERR, CAM_SCSI_STATUS_ERROR}, 91579697Snon {BUSYERR | STATERR, CAM_SCSI_STATUS_ERROR}, 91679697Snon {SELTIMEOUTIO, CAM_SEL_TIMEOUT}, 91779697Snon {TIMEOUTIO, CAM_CMD_TIMEOUT}, 91879697Snon {PDMAERR, CAM_DATA_RUN_ERR}, 91979697Snon {PARITYERR, CAM_UNCOR_PARITY}, 92079697Snon {UBFERR, CAM_UNEXP_BUSFREE}, 92179697Snon {ABORTIO, CAM_REQ_ABORTED}, 92279697Snon {-1, CAM_UNREC_HBA_ERROR} 92379697Snon}; 92479697Snon 92579697Snon#define SIM2SLP(sim) ((struct scsi_low_softc *) cam_sim_softc((sim))) 92679697Snon 92779697Snon/* XXX: 92879697Snon * Please check a polling hz, currently we assume scsi_low_poll() is 92979697Snon * called each 1 ms. 93079697Snon */ 93179697Snon#define SCSI_LOW_CAM_POLL_HZ 1000 /* OK ? */ 93279697Snon 93379697Snonstatic void 93479697Snonscsi_low_poll_cam(sim) 93579697Snon struct cam_sim *sim; 93679697Snon{ 93779697Snon struct scsi_low_softc *slp = SIM2SLP(sim); 93879697Snon 93979697Snon (*slp->sl_funcs->scsi_low_poll) (slp); 94079697Snon 94179697Snon if (slp->sl_si.si_poll_count ++ >= 94279697Snon SCSI_LOW_CAM_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) 94379697Snon { 94479697Snon slp->sl_si.si_poll_count = 0; 94579697Snon scsi_low_timeout_check(slp); 94679697Snon } 94779697Snon} 94879697Snon 94979697Snonstatic void 95079697Snonscsi_low_cam_rescan_callback(periph, ccb) 95179697Snon struct cam_periph *periph; 95279697Snon union ccb *ccb; 95379697Snon{ 95479697Snon 95579697Snon xpt_free_path(ccb->ccb_h.path); 95679697Snon free(ccb, M_DEVBUF); 95779697Snon} 95879697Snon 95979697Snonstatic void 96079697Snonscsi_low_rescan_bus_cam(slp) 96179697Snon struct scsi_low_softc *slp; 96279697Snon{ 96379697Snon struct cam_path *path; 96479697Snon union ccb *ccb = malloc(sizeof(union ccb), M_DEVBUF, M_WAITOK); 96579697Snon cam_status status; 96679697Snon 96779697Snon bzero(ccb, sizeof(union ccb)); 96879697Snon 96979697Snon status = xpt_create_path(&path, xpt_periph, 97079697Snon cam_sim_path(slp->sl_si.sim), -1, 0); 97179697Snon if (status != CAM_REQ_CMP) 97279697Snon return; 97379697Snon 97479697Snon xpt_setup_ccb(&ccb->ccb_h, path, 5); 97579697Snon ccb->ccb_h.func_code = XPT_SCAN_BUS; 97679697Snon ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback; 97779697Snon ccb->crcn.flags = CAM_FLAG_NONE; 97879697Snon xpt_action(ccb); 97979697Snon} 98079697Snon 98179697Snonvoid 98279697Snonscsi_low_scsi_action_cam(sim, ccb) 98379697Snon struct cam_sim *sim; 98479697Snon union ccb *ccb; 98579697Snon{ 98679697Snon struct scsi_low_softc *slp = SIM2SLP(sim); 98779697Snon struct targ_info *ti; 98879697Snon struct lun_info *li; 98979697Snon struct slccb *cb; 99079697Snon u_int lun, flags, msg, target; 99179697Snon int s, rv; 99279697Snon 99379697Snon target = (u_int) (ccb->ccb_h.target_id); 99479697Snon lun = (u_int) ccb->ccb_h.target_lun; 99579697Snon 99679697Snon#ifdef SCSI_LOW_DEBUG 99779697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_ACTION, target) != 0) 99879697Snon { 99979697Snon printf("%s: cam_action: func code 0x%x target: %d, lun: %d\n", 100079697Snon slp->sl_xname, ccb->ccb_h.func_code, target, lun); 100179697Snon } 100279697Snon#endif /* SCSI_LOW_DEBUG */ 100379697Snon 100479697Snon switch (ccb->ccb_h.func_code) { 100579697Snon case XPT_SCSI_IO: /* Execute the requested I/O operation */ 100679697Snon#ifdef SCSI_LOW_DIAGNOSTIC 100779697Snon if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD) 100879697Snon { 100979697Snon printf("%s: invalid target/lun\n", slp->sl_xname); 101079697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 101179697Snon xpt_done(ccb); 101279697Snon return; 101379697Snon } 101479697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 101579697Snon 101679697Snon if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) { 101779697Snon ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 101879697Snon xpt_done(ccb); 101979697Snon return; 102079697Snon } 102179697Snon 102279697Snon ti = slp->sl_ti[target]; 102379697Snon cb->osdep = ccb; 102479697Snon cb->bp = NULL; 102579697Snon if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) 102679697Snon flags = CCB_AUTOSENSE | CCB_SCSIIO; 102779697Snon else 102879697Snon flags = CCB_SCSIIO; 102979697Snon 103079697Snon s = SCSI_LOW_SPLSCSI(); 103179697Snon li = scsi_low_alloc_li(ti, lun, 1); 103279697Snon 103379697Snon if (ti->ti_setup_msg != 0) 103479697Snon { 103579697Snon scsi_low_message_enqueue(slp, ti, li, CCB_AUTOSENSE); 103679697Snon } 103779697Snon 103879697Snon scsi_low_enqueue(slp, ti, li, cb, flags, 0); 103979697Snon 104079697Snon#ifdef SCSI_LOW_DEBUG 104179697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, target) != 0) 104279697Snon { 104379697Snon scsi_low_test_abort(slp, ti, li); 104479697Snon } 104579697Snon#endif /* SCSI_LOW_DEBUG */ 104679697Snon splx(s); 104779697Snon break; 104879697Snon 104979697Snon case XPT_EN_LUN: /* Enable LUN as a target */ 105079697Snon case XPT_TARGET_IO: /* Execute target I/O request */ 105179697Snon case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 105279697Snon case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 105379697Snon /* XXX Implement */ 105479697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 105579697Snon xpt_done(ccb); 105679697Snon break; 105779697Snon 105879697Snon case XPT_ABORT: /* Abort the specified CCB */ 105979697Snon#ifdef SCSI_LOW_DIAGNOSTIC 106079697Snon if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD) 106179697Snon { 106279697Snon printf("%s: invalid target/lun\n", slp->sl_xname); 106379697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 106479697Snon xpt_done(ccb); 106579697Snon return; 106679697Snon } 106779697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 106879697Snon 106979697Snon s = SCSI_LOW_SPLSCSI(); 107079697Snon cb = scsi_low_find_ccb(slp, target, lun, ccb->cab.abort_ccb); 107179697Snon rv = scsi_low_abort_ccb(slp, cb); 107279697Snon splx(s); 107379697Snon 107479697Snon if (rv == 0) 107579697Snon ccb->ccb_h.status = CAM_REQ_CMP; 107679697Snon else 107779697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 107879697Snon xpt_done(ccb); 107979697Snon break; 108079697Snon 108179697Snon case XPT_SET_TRAN_SETTINGS: { 108279697Snon struct ccb_trans_settings *cts; 108379697Snon u_int val; 108479697Snon 108579697Snon#ifdef SCSI_LOW_DIAGNOSTIC 108679697Snon if (target == CAM_TARGET_WILDCARD) 108779697Snon { 108879697Snon printf("%s: invalid target\n", slp->sl_xname); 108979697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 109079697Snon xpt_done(ccb); 109179697Snon return; 109279697Snon } 109379697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 109479697Snon cts = &ccb->cts; 109579697Snon ti = slp->sl_ti[target]; 109679697Snon if (lun == CAM_LUN_WILDCARD) 109779697Snon lun = 0; 109879697Snon 109979697Snon s = SCSI_LOW_SPLSCSI(); 110079697Snon if ((cts->valid & (CCB_TRANS_BUS_WIDTH_VALID | 110179697Snon CCB_TRANS_SYNC_RATE_VALID | 110279697Snon CCB_TRANS_SYNC_OFFSET_VALID)) != 0) 110379697Snon { 110479697Snon if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { 110579697Snon val = cts->bus_width; 110679697Snon if (val < ti->ti_width) 110779697Snon ti->ti_width = val; 110879697Snon } 110979697Snon if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) { 111079697Snon val = cts->sync_period; 111179697Snon if (val == 0 || val > ti->ti_maxsynch.period) 111279697Snon ti->ti_maxsynch.period = val; 111379697Snon } 111479697Snon if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) { 111579697Snon val = cts->sync_offset; 111679697Snon if (val < ti->ti_maxsynch.offset) 111779697Snon ti->ti_maxsynch.offset = val; 111879697Snon } 111979697Snon 112079697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 112179697Snon scsi_low_calcf_target(ti); 112279697Snon } 112379697Snon 112479697Snon if ((cts->valid & (CCB_TRANS_DISC_VALID | 112579697Snon CCB_TRANS_TQ_VALID)) != 0) 112679697Snon { 112779697Snon li = scsi_low_alloc_li(ti, lun, 1); 112879697Snon if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) 112979697Snon { 113079697Snon if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 113179697Snon li->li_quirks |= SCSI_LOW_DISK_DISC; 113279697Snon else 113379697Snon li->li_quirks &= ~SCSI_LOW_DISK_DISC; 113479697Snon } 113579697Snon if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) 113679697Snon { 113779697Snon if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 113879697Snon li->li_quirks |= SCSI_LOW_DISK_QTAG; 113979697Snon else 114079697Snon li->li_quirks &= ~SCSI_LOW_DISK_QTAG; 114179697Snon } 114279697Snon 114379697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 114479697Snon scsi_low_calcf_target(ti); 114579697Snon scsi_low_calcf_lun(li); 114679697Snon if ((slp->sl_show_result & SHOW_CALCF_RES) != 0) 114779697Snon scsi_low_calcf_show(li); 114879697Snon } 114979697Snon splx(s); 115079697Snon 115179697Snon ccb->ccb_h.status = CAM_REQ_CMP; 115279697Snon xpt_done(ccb); 115379697Snon break; 115479697Snon } 115579697Snon 115679697Snon case XPT_GET_TRAN_SETTINGS: { 115779697Snon struct ccb_trans_settings *cts; 115879697Snon u_int diskflags; 115979697Snon 116079697Snon cts = &ccb->cts; 116179697Snon#ifdef SCSI_LOW_DIAGNOSTIC 116279697Snon if (target == CAM_TARGET_WILDCARD) 116379697Snon { 116479697Snon printf("%s: invalid target\n", slp->sl_xname); 116579697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 116679697Snon xpt_done(ccb); 116779697Snon return; 116879697Snon } 116979697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 117079697Snon ti = slp->sl_ti[target]; 117179697Snon if (lun == CAM_LUN_WILDCARD) 117279697Snon lun = 0; 117379697Snon 117479697Snon s = SCSI_LOW_SPLSCSI(); 117579697Snon li = scsi_low_alloc_li(ti, lun, 1); 117679697Snon#ifdef CAM_NEW_TRAN_CODE 117779697Snon if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) { 117879697Snon struct ccb_trans_settings_scsi *scsi = 117979697Snon &cts->proto_specific.scsi; 118079697Snon struct ccb_trans_settings_spi *spi = 118179697Snon &cts->xport_specific.spi; 118279697Snon#ifdef SCSI_LOW_DIAGNOSTIC 118379697Snon if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID) 118479697Snon { 118579697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 118679697Snon printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n", 118779697Snon slp->sl_xname); 118879697Snon goto settings_out; 118979697Snon } 119079697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 119179697Snon cts->protocol = PROTO_SCSI; 119279697Snon cts->protocol_version = SCSI_REV_2; 119379697Snon cts->transport = XPORT_SPI; 119479697Snon cts->transport_version = 2; 119579697Snon 119679697Snon scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 119779697Snon spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 119879697Snon 119979697Snon diskflags = li->li_diskflags & li->li_cfgflags; 120079697Snon if (diskflags & SCSI_LOW_DISK_DISC) 120179697Snon spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 120279697Snon if (diskflags & SCSI_LOW_DISK_QTAG) 120379697Snon scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 120479697Snon 120579697Snon spi->sync_period = ti->ti_maxsynch.period; 120679697Snon spi->valid |= CTS_SPI_VALID_SYNC_RATE; 120779697Snon spi->sync_offset = ti->ti_maxsynch.offset; 120879697Snon spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 120979697Snon 121079697Snon spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 121179697Snon spi->bus_width = ti->ti_width; 121279697Snon 121379697Snon if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 121479697Snon scsi->valid = CTS_SCSI_VALID_TQ; 121579697Snon spi->valid |= CTS_SPI_VALID_DISC; 121679697Snon } else 121779697Snon scsi->valid = 0; 121879697Snon } else 121979697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 122079697Snon#else 122179697Snon if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) 122279697Snon { 122379697Snon#ifdef SCSI_LOW_DIAGNOSTIC 122479697Snon if ((li->li_flags_valid & SCSI_LOW_LUN_FLAGS_DISK_VALID) == 0) 122579697Snon { 122679697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 122779697Snon printf("%s: invalid GET_TRANS_USER_SETTINGS call\n", 122879697Snon slp->sl_xname); 122979697Snon goto settings_out; 123079697Snon } 123179697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 123279697Snon diskflags = li->li_diskflags & li->li_cfgflags; 123379697Snon if ((diskflags & SCSI_LOW_DISK_DISC) != 0) 123479697Snon cts->flags |= CCB_TRANS_DISC_ENB; 123579697Snon else 123679697Snon cts->flags &= ~CCB_TRANS_DISC_ENB; 123779697Snon if ((diskflags & SCSI_LOW_DISK_QTAG) != 0) 123879697Snon cts->flags |= CCB_TRANS_TAG_ENB; 123979697Snon else 124079697Snon cts->flags &= ~CCB_TRANS_TAG_ENB; 124179697Snon } 124279697Snon else if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) 124379697Snon { 124479697Snon#ifdef SCSI_LOW_DIAGNOSTIC 124579697Snon if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID) 124679697Snon { 124779697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 124879697Snon printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n", 124979697Snon slp->sl_xname); 125079697Snon goto settings_out; 125179697Snon } 125279697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 125379697Snon if ((li->li_flags & SCSI_LOW_DISC) != 0) 125479697Snon cts->flags |= CCB_TRANS_DISC_ENB; 125579697Snon else 125679697Snon cts->flags &= ~CCB_TRANS_DISC_ENB; 125779697Snon if ((li->li_flags & SCSI_LOW_QTAG) != 0) 125879697Snon cts->flags |= CCB_TRANS_TAG_ENB; 125979697Snon else 126079697Snon cts->flags &= ~CCB_TRANS_TAG_ENB; 126179697Snon } 126279697Snon else 126379697Snon { 126479697Snon ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 126579697Snon goto settings_out; 126679697Snon } 126779697Snon 126879697Snon cts->sync_period = ti->ti_maxsynch.period; 126979697Snon cts->sync_offset = ti->ti_maxsynch.offset; 127079697Snon cts->bus_width = ti->ti_width; 127179697Snon 127279697Snon cts->valid = CCB_TRANS_SYNC_RATE_VALID 127379697Snon | CCB_TRANS_SYNC_OFFSET_VALID 127479697Snon | CCB_TRANS_BUS_WIDTH_VALID 127579697Snon | CCB_TRANS_DISC_VALID 127679697Snon | CCB_TRANS_TQ_VALID; 127779697Snon ccb->ccb_h.status = CAM_REQ_CMP; 127879697Snon#endif 127979697Snonsettings_out: 128079697Snon splx(s); 128179697Snon xpt_done(ccb); 128279697Snon break; 128379697Snon } 128479697Snon 128579697Snon case XPT_CALC_GEOMETRY: { /* not yet HN2 */ 128679697Snon struct ccb_calc_geometry *ccg; 128779697Snon u_int32_t size_mb; 128879697Snon u_int32_t secs_per_cylinder; 128979697Snon int extended; 129079697Snon 129179697Snon extended = 1; 129279697Snon ccg = &ccb->ccg; 129379697Snon size_mb = ccg->volume_size 129479697Snon / ((1024L * 1024L) / ccg->block_size); 129579697Snon 129679697Snon if (size_mb > 1024 && extended) { 129779697Snon ccg->heads = 255; 129879697Snon ccg->secs_per_track = 63; 129979697Snon } else { 130079697Snon ccg->heads = 64; 130179697Snon ccg->secs_per_track = 32; 130279697Snon } 130379697Snon secs_per_cylinder = ccg->heads * ccg->secs_per_track; 130479697Snon ccg->cylinders = ccg->volume_size / secs_per_cylinder; 130579697Snon ccb->ccb_h.status = CAM_REQ_CMP; 130679697Snon xpt_done(ccb); 130779697Snon break; 130879697Snon } 130979697Snon 131079697Snon case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 131179697Snon s = SCSI_LOW_SPLSCSI(); 131279697Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL); 131379697Snon splx(s); 131479697Snon ccb->ccb_h.status = CAM_REQ_CMP; 131579697Snon xpt_done(ccb); 131679697Snon break; 131779697Snon 131879697Snon case XPT_TERM_IO: /* Terminate the I/O process */ 131979697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 132079697Snon xpt_done(ccb); 132179697Snon break; 132279697Snon 132379697Snon case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 132479697Snon#ifdef SCSI_LOW_DIAGNOSTIC 132579697Snon if (target == CAM_TARGET_WILDCARD) 132679697Snon { 132779697Snon printf("%s: invalid target\n", slp->sl_xname); 132879697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 132979697Snon xpt_done(ccb); 133079697Snon return; 133179697Snon } 133279697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 133379697Snon 133479697Snon msg = SCSI_LOW_MSG_RESET; 133579697Snon if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) 133679697Snon { 133779697Snon ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 133879697Snon xpt_done(ccb); 133979697Snon return; 134079697Snon } 134179697Snon 134279697Snon ti = slp->sl_ti[target]; 134379697Snon if (lun == CAM_LUN_WILDCARD) 134479697Snon lun = 0; 134579697Snon cb->osdep = ccb; 134679697Snon cb->bp = NULL; 134779697Snon if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) 134879697Snon flags = CCB_AUTOSENSE | CCB_NORETRY | CCB_URGENT; 134979697Snon else 135079697Snon flags = CCB_NORETRY | CCB_URGENT; 135179697Snon 135279697Snon s = SCSI_LOW_SPLSCSI(); 135379697Snon li = scsi_low_alloc_li(ti, lun, 1); 135479697Snon scsi_low_enqueue(slp, ti, li, cb, flags, msg); 135579697Snon splx(s); 135679697Snon break; 135779697Snon 135879697Snon case XPT_PATH_INQ: { /* Path routing inquiry */ 135979697Snon struct ccb_pathinq *cpi = &ccb->cpi; 136079697Snon 136179697Snon cpi->version_num = scsi_low_version_major; 136279697Snon cpi->hba_inquiry = PI_TAG_ABLE | PI_LINKED_CDB; 136379697Snon ti = slp->sl_ti[slp->sl_hostid]; /* host id */ 136479697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 136579697Snon cpi->hba_inquiry |= PI_WIDE_16; 136679697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_16) 136779697Snon cpi->hba_inquiry |= PI_WIDE_32; 136879697Snon if (ti->ti_maxsynch.offset > 0) 136979697Snon cpi->hba_inquiry |= PI_SDTR_ABLE; 137079697Snon cpi->target_sprt = 0; 137179697Snon cpi->hba_misc = 0; 137279697Snon cpi->hba_eng_cnt = 0; 137379697Snon cpi->max_target = slp->sl_ntargs - 1; 137479697Snon cpi->max_lun = slp->sl_nluns - 1; 137579697Snon cpi->initiator_id = slp->sl_hostid; 137679697Snon cpi->bus_id = cam_sim_bus(sim); 137779697Snon cpi->base_transfer_speed = 3300; 137879697Snon#ifdef CAM_NEW_TRAN_CODE 137979697Snon cpi->transport = XPORT_SPI; 138079697Snon cpi->transport_version = 2; 138179697Snon cpi->protocol = PROTO_SCSI; 138279697Snon cpi->protocol_version = SCSI_REV_2; 138379697Snon#endif 138479697Snon strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 138579697Snon strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN); 138679697Snon strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 138779697Snon cpi->unit_number = cam_sim_unit(sim); 138879697Snon cpi->ccb_h.status = CAM_REQ_CMP; 138979697Snon xpt_done(ccb); 139079697Snon break; 139179697Snon } 139279697Snon 139379697Snon default: 139479697Snon printf("scsi_low: non support func_code = %d ", 139579697Snon ccb->ccb_h.func_code); 139679697Snon ccb->ccb_h.status = CAM_REQ_INVALID; 139779697Snon xpt_done(ccb); 139879697Snon break; 139979697Snon } 140079697Snon} 140179697Snon 140279697Snonstatic int 140379697Snonscsi_low_attach_cam(slp) 140479697Snon struct scsi_low_softc *slp; 140579697Snon{ 140679697Snon struct cam_devq *devq; 140779697Snon int tagged_openings; 140879697Snon 140979697Snon sprintf(slp->sl_xname, "%s%d", 141079697Snon DEVPORT_DEVNAME(slp->sl_dev), DEVPORT_DEVUNIT(slp->sl_dev)); 141179697Snon 141279697Snon devq = cam_simq_alloc(SCSI_LOW_NCCB); 141379697Snon if (devq == NULL) 141479697Snon return (ENOMEM); 141579697Snon 141679697Snon /* 141779697Snon * ask the adapter what subunits are present 141879697Snon */ 141979697Snon tagged_openings = min(slp->sl_openings, SCSI_LOW_MAXNEXUS); 142079697Snon slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam, 142179697Snon scsi_low_poll_cam, 142279697Snon DEVPORT_DEVNAME(slp->sl_dev), slp, 142379697Snon DEVPORT_DEVUNIT(slp->sl_dev), 142479697Snon slp->sl_openings, tagged_openings, devq); 142579697Snon 142679697Snon if (slp->sl_si.sim == NULL) { 142779697Snon cam_simq_free(devq); 142879697Snon return ENODEV; 142979697Snon } 143079697Snon 143179697Snon if (xpt_bus_register(slp->sl_si.sim, 0) != CAM_SUCCESS) { 143279697Snon free(slp->sl_si.sim, M_DEVBUF); 143379697Snon return ENODEV; 143479697Snon } 143579697Snon 143679697Snon if (xpt_create_path(&slp->sl_si.path, /*periph*/NULL, 143779697Snon cam_sim_path(slp->sl_si.sim), CAM_TARGET_WILDCARD, 143879697Snon CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 143979697Snon xpt_bus_deregister(cam_sim_path(slp->sl_si.sim)); 144079697Snon cam_sim_free(slp->sl_si.sim, /*free_simq*/TRUE); 144179697Snon free(slp->sl_si.sim, M_DEVBUF); 144279697Snon return ENODEV; 144379697Snon } 144479697Snon 144579697Snon slp->sl_show_result = SHOW_CALCF_RES; /* OK ? */ 144679697Snon return 0; 144779697Snon} 144879697Snon 144979697Snonstatic int 145079697Snonscsi_low_world_start_cam(slp) 145179697Snon struct scsi_low_softc *slp; 145279697Snon{ 145379697Snon 145479697Snon if (!cold) 145579697Snon scsi_low_rescan_bus_cam(slp); 145679697Snon return 0; 145779697Snon} 145879697Snon 145979697Snonstatic int 146079697Snonscsi_low_dettach_cam(slp) 146179697Snon struct scsi_low_softc *slp; 146279697Snon{ 146379697Snon 146479697Snon xpt_async(AC_LOST_DEVICE, slp->sl_si.path, NULL); 146579697Snon xpt_free_path(slp->sl_si.path); 146679697Snon xpt_bus_deregister(cam_sim_path(slp->sl_si.sim)); 146779697Snon cam_sim_free(slp->sl_si.sim, /* free_devq */ TRUE); 146879697Snon return 0; 146979697Snon} 147079697Snon 147179697Snonstatic int 147279697Snonscsi_low_ccb_setup_cam(slp, cb) 147379697Snon struct scsi_low_softc *slp; 147479697Snon struct slccb *cb; 147579697Snon{ 147679697Snon union ccb *ccb = (union ccb *) cb->osdep; 147779697Snon 147879697Snon if ((cb->ccb_flags & CCB_SCSIIO) != 0) 147979697Snon { 148079697Snon cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes; 148179697Snon cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len; 148279697Snon cb->ccb_scp.scp_data = ccb->csio.data_ptr; 148379697Snon cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len; 148479697Snon if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 148579697Snon cb->ccb_scp.scp_direction = SCSI_LOW_WRITE; 148679697Snon else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */ 148779697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 148879697Snon cb->ccb_tcmax = ccb->ccb_h.timeout / 1000; 148979697Snon } 149079697Snon else 149179697Snon { 149279697Snon scsi_low_unit_ready_cmd(cb); 149379697Snon } 149479697Snon return SCSI_LOW_START_QTAG; 149579697Snon} 149679697Snon 149779697Snonstatic int 149879697Snonscsi_low_done_cam(slp, cb) 149979697Snon struct scsi_low_softc *slp; 150079697Snon struct slccb *cb; 150179697Snon{ 150279697Snon union ccb *ccb; 150379697Snon 150479697Snon ccb = (union ccb *) cb->osdep; 150579697Snon if (cb->ccb_error == 0) 150679697Snon { 150779697Snon ccb->ccb_h.status = CAM_REQ_CMP; 150879697Snon ccb->csio.resid = 0; 150979697Snon } 151079697Snon else 151179697Snon { 151279697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 151379697Snon cb->ccb_error |= ABORTIO; 151479697Snon 151579697Snon if ((cb->ccb_flags & CCB_NORETRY) == 0 && 151679697Snon (cb->ccb_error & ABORTIO) == 0) 151779697Snon return EJUSTRETURN; 151879697Snon 151979697Snon if ((cb->ccb_error & SENSEIO) != 0) 152079697Snon { 152179697Snon memcpy(&ccb->csio.sense_data, 152279697Snon &cb->ccb_sense, 152379697Snon sizeof(ccb->csio.sense_data)); 152479697Snon } 152579697Snon 152679697Snon ccb->ccb_h.status = scsi_low_translate_error_code(cb, 152779697Snon &scsi_low_error_code_cam[0]); 152879697Snon 152979697Snon#ifdef SCSI_LOW_DIAGNOSTIC 153079697Snon if ((cb->ccb_flags & CCB_SILENT) == 0 && 153179697Snon cb->ccb_scp.scp_cmdlen > 0 && 153279697Snon (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 153379697Snon SCSI_LOW_CMD_ABORT_WARNING) != 0) 153479697Snon { 153579697Snon printf("%s: WARNING: scsi_low IO abort\n", 153679697Snon slp->sl_xname); 153779697Snon scsi_low_print(slp, NULL); 153879697Snon } 153979697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 154079697Snon } 154179697Snon 154279697Snon if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0) 154379697Snon ccb->ccb_h.status |= CAM_REQ_CMP_ERR; 154479697Snon 154579697Snon if (cb->ccb_scp.scp_status == ST_UNKNOWN) 154679697Snon ccb->csio.scsi_status = 0; /* XXX */ 154779697Snon else 154879697Snon ccb->csio.scsi_status = cb->ccb_scp.scp_status; 154979697Snon 155079697Snon if ((cb->ccb_flags & CCB_NOSDONE) == 0) 155179697Snon xpt_done(ccb); 155279697Snon return 0; 155379697Snon} 155479697Snon 155579697Snonstatic void 155679697Snonscsi_low_timeout_cam(slp, ch, action) 155779697Snon struct scsi_low_softc *slp; 155879697Snon int ch; 155979697Snon int action; 156079697Snon{ 156179697Snon 156279697Snon switch (ch) 156379697Snon { 156479697Snon case SCSI_LOW_TIMEOUT_CH_IO: 156579697Snon switch (action) 156679697Snon { 156779697Snon case SCSI_LOW_TIMEOUT_START: 156879697Snon slp->sl_si.timeout_ch = timeout(scsi_low_timeout, slp, 156979697Snon hz / SCSI_LOW_TIMEOUT_HZ); 157079697Snon break; 157179697Snon case SCSI_LOW_TIMEOUT_STOP: 157279697Snon untimeout(scsi_low_timeout, slp, slp->sl_si.timeout_ch); 157379697Snon break; 157479697Snon } 157579697Snon break; 157679697Snon 157779697Snon case SCSI_LOW_TIMEOUT_CH_ENGAGE: 157879697Snon switch (action) 157979697Snon { 158079697Snon case SCSI_LOW_TIMEOUT_START: 158179697Snon slp->sl_si.engage_ch = timeout(scsi_low_engage, slp, 1); 158279697Snon break; 158379697Snon case SCSI_LOW_TIMEOUT_STOP: 158479697Snon untimeout(scsi_low_engage, slp, slp->sl_si.engage_ch); 158579697Snon break; 158679697Snon } 158779697Snon break; 158879697Snon case SCSI_LOW_TIMEOUT_CH_RECOVER: 158979697Snon break; 159079697Snon } 159179697Snon} 159279697Snon 159379697Snon#endif /* SCSI_LOW_INTERFACE_CAM */ 159479697Snon 159579697Snon/*============================================================= 159679697Snon * END OF OS switch (All OS depend fucntions should be above) 159779697Snon =============================================================*/ 159879697Snon 159979697Snon/************************************************************** 160079697Snon * scsi low deactivate and activate 160179697Snon **************************************************************/ 160279697Snonint 160379697Snonscsi_low_is_busy(slp) 160479697Snon struct scsi_low_softc *slp; 160579697Snon{ 160679697Snon 160779697Snon if (slp->sl_nio > 0) 160879697Snon return EBUSY; 160979697Snon return 0; 161079697Snon} 161179697Snon 161279697Snonint 161379697Snonscsi_low_deactivate(slp) 161479697Snon struct scsi_low_softc *slp; 161579697Snon{ 161679697Snon int s; 161779697Snon 161879697Snon s = SCSI_LOW_SPLSCSI(); 161979697Snon slp->sl_flags |= HW_INACTIVE; 162079697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 162179697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_STOP); 162279697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 162379697Snon (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP); 162479697Snon splx(s); 162579697Snon return 0; 162679697Snon} 162779697Snon 162879697Snonint 162979697Snonscsi_low_activate(slp) 163079697Snon struct scsi_low_softc *slp; 163179697Snon{ 163279697Snon int error, s; 163379697Snon 163479697Snon s = SCSI_LOW_SPLSCSI(); 163579697Snon slp->sl_flags &= ~HW_INACTIVE; 163679697Snon if ((error = scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL)) != 0) 163779697Snon { 163879697Snon slp->sl_flags |= HW_INACTIVE; 163979697Snon splx(s); 164079697Snon return error; 164179697Snon } 164279697Snon 164379697Snon slp->sl_timeout_count = 0; 164479697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 164579697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 164679697Snon splx(s); 164779697Snon return 0; 164879697Snon} 164979697Snon 165079697Snon/************************************************************** 165179697Snon * scsi low log 165279697Snon **************************************************************/ 165379697Snon#ifdef SCSI_LOW_DIAGNOSTIC 165492770Salfredstatic void scsi_low_msg_log_init(struct scsi_low_msg_log *); 165592770Salfredstatic void scsi_low_msg_log_write(struct scsi_low_msg_log *, u_int8_t *, int); 165692770Salfredstatic void scsi_low_msg_log_show(struct scsi_low_msg_log *, char *, int); 165779697Snon 165879697Snonstatic void 165979697Snonscsi_low_msg_log_init(slmlp) 166079697Snon struct scsi_low_msg_log *slmlp; 166179697Snon{ 166279697Snon 166379697Snon slmlp->slml_ptr = 0; 166479697Snon} 166579697Snon 166679697Snonstatic void 166779697Snonscsi_low_msg_log_write(slmlp, datap, len) 166879697Snon struct scsi_low_msg_log *slmlp; 166979697Snon u_int8_t *datap; 167079697Snon int len; 167179697Snon{ 167279697Snon int ptr, ind; 167379697Snon 167479697Snon if (slmlp->slml_ptr >= SCSI_LOW_MSG_LOG_DATALEN) 167579697Snon return; 167679697Snon 167779697Snon ptr = slmlp->slml_ptr ++; 167879697Snon for (ind = 0; ind < sizeof(slmlp->slml_msg[0]) && ind < len; ind ++) 167979697Snon slmlp->slml_msg[ptr].msg[ind] = datap[ind]; 168079697Snon for ( ; ind < sizeof(slmlp->slml_msg[0]); ind ++) 168179697Snon slmlp->slml_msg[ptr].msg[ind] = 0; 168279697Snon} 168379697Snon 168479697Snonstatic void 168579697Snonscsi_low_msg_log_show(slmlp, s, len) 168679697Snon struct scsi_low_msg_log *slmlp; 168779697Snon char *s; 168879697Snon int len; 168979697Snon{ 169079697Snon int ptr, ind; 169179697Snon 169279697Snon printf("%s: (%d) ", s, slmlp->slml_ptr); 169379697Snon for (ptr = 0; ptr < slmlp->slml_ptr; ptr ++) 169479697Snon { 169579697Snon for (ind = 0; ind < len && ind < sizeof(slmlp->slml_msg[0]); 169679697Snon ind ++) 169779697Snon { 169879697Snon printf("[%x]", (u_int) slmlp->slml_msg[ptr].msg[ind]); 169979697Snon } 170079697Snon printf(">"); 170179697Snon } 170279697Snon printf("\n"); 170379697Snon} 170479697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 170579697Snon 170679697Snon/************************************************************** 170767468Snon * power control 170867468Snon **************************************************************/ 170967468Snonstatic void 171067468Snonscsi_low_engage(arg) 171167468Snon void *arg; 171267468Snon{ 171367468Snon struct scsi_low_softc *slp = arg; 171479697Snon int s = SCSI_LOW_SPLSCSI(); 171567468Snon 171667468Snon switch (slp->sl_rstep) 171767468Snon { 171867468Snon case 0: 171967468Snon slp->sl_rstep ++; 172067468Snon (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); 172179697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp, 172279697Snon SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_START); 172367468Snon break; 172467468Snon 172567468Snon case 1: 172667468Snon slp->sl_rstep ++; 172767468Snon slp->sl_flags &= ~HW_RESUME; 172867468Snon scsi_low_start(slp); 172967468Snon break; 173067468Snon 173167468Snon case 2: 173267468Snon break; 173367468Snon } 173467468Snon splx(s); 173567468Snon} 173667468Snon 173767468Snonstatic int 173867468Snonscsi_low_init(slp, flags) 173967468Snon struct scsi_low_softc *slp; 174067468Snon u_int flags; 174167468Snon{ 174279697Snon int rv = 0; 174367468Snon 174479697Snon slp->sl_flags |= HW_INITIALIZING; 174579697Snon 174679697Snon /* clear power control timeout */ 174767468Snon if ((slp->sl_flags & HW_POWERCTRL) != 0) 174867468Snon { 174979697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp, 175079697Snon SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP); 175167468Snon slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME); 175267468Snon slp->sl_active = 1; 175367468Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 175467468Snon } 175567468Snon 175667468Snon /* reset current nexus */ 175767468Snon scsi_low_reset_nexus(slp, flags); 175867468Snon if ((slp->sl_flags & HW_INACTIVE) != 0) 175979697Snon { 176079697Snon rv = EBUSY; 176179697Snon goto out; 176279697Snon } 176367468Snon 176479697Snon if (flags != SCSI_LOW_RESTART_SOFT) 176579697Snon { 176679697Snon rv = ((*slp->sl_funcs->scsi_low_init) (slp, flags)); 176779697Snon } 176867468Snon 176979697Snonout: 177079697Snon slp->sl_flags &= ~HW_INITIALIZING; 177179697Snon return rv; 177267468Snon} 177367468Snon 177467468Snon/************************************************************** 177567468Snon * allocate lun_info 177667468Snon **************************************************************/ 177767468Snonstatic struct lun_info * 177867468Snonscsi_low_alloc_li(ti, lun, alloc) 177967468Snon struct targ_info *ti; 178067468Snon int lun; 178167468Snon int alloc; 178267468Snon{ 178379697Snon struct scsi_low_softc *slp = ti->ti_sc; 178467468Snon struct lun_info *li; 178567468Snon 178667468Snon li = LIST_FIRST(&ti->ti_litab); 178767468Snon if (li != NULL) 178867468Snon { 178967468Snon if (li->li_lun == lun) 179067468Snon return li; 179167468Snon 179267468Snon while ((li = LIST_NEXT(li, lun_chain)) != NULL) 179367468Snon { 179467468Snon if (li->li_lun == lun) 179567468Snon { 179667468Snon LIST_REMOVE(li, lun_chain); 179767468Snon LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); 179867468Snon return li; 179967468Snon } 180067468Snon } 180167468Snon } 180267468Snon 180367468Snon if (alloc == 0) 180467468Snon return li; 180567468Snon 180679697Snon li = SCSI_LOW_MALLOC(ti->ti_lunsize); 180767468Snon if (li == NULL) 180867468Snon panic("no lun info mem\n"); 180967468Snon 181079697Snon SCSI_LOW_BZERO(li, ti->ti_lunsize); 181167468Snon li->li_lun = lun; 181267468Snon li->li_ti = ti; 181367468Snon 181479697Snon li->li_cfgflags = SCSI_LOW_SYNC | SCSI_LOW_LINK | SCSI_LOW_DISC | 181579697Snon SCSI_LOW_QTAG; 181679697Snon li->li_quirks = li->li_diskflags = SCSI_LOW_DISK_LFLAGS; 181779697Snon li->li_flags_valid = SCSI_LOW_LUN_FLAGS_USER_VALID; 181879697Snon#ifdef SCSI_LOW_FLAGS_QUIRKS_OK 181979697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID; 182079697Snon#endif /* SCSI_LOW_FLAGS_QUIRKS_OK */ 182179697Snon 182279697Snon li->li_qtagbits = (u_int) -1; 182379697Snon 182479697Snon TAILQ_INIT(&li->li_discq); 182567468Snon LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); 182667468Snon 182779697Snon /* host specific structure initialization per lun */ 182879697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 182979697Snon (*slp->sl_funcs->scsi_low_lun_init) 183079697Snon (slp, ti, li, SCSI_LOW_INFO_ALLOC); 183179697Snon scsi_low_calcf_lun(li); 183267468Snon return li; 183367468Snon} 183467468Snon 183567468Snon/************************************************************** 183667468Snon * allocate targ_info 183767468Snon **************************************************************/ 183867468Snonstatic struct targ_info * 183979697Snonscsi_low_alloc_ti(slp, targ) 184067468Snon struct scsi_low_softc *slp; 184179697Snon int targ; 184267468Snon{ 184367468Snon struct targ_info *ti; 184467468Snon 184571999Sphk if (TAILQ_FIRST(&slp->sl_titab) == NULL) 184667468Snon TAILQ_INIT(&slp->sl_titab); 184767468Snon 184879697Snon ti = SCSI_LOW_MALLOC(slp->sl_targsize); 184967468Snon if (ti == NULL) 185067468Snon panic("%s short of memory\n", slp->sl_xname); 185167468Snon 185279697Snon SCSI_LOW_BZERO(ti, slp->sl_targsize); 185367468Snon ti->ti_id = targ; 185467468Snon ti->ti_sc = slp; 185567468Snon 185667468Snon slp->sl_ti[targ] = ti; 185767468Snon TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain); 185867468Snon LIST_INIT(&ti->ti_litab); 185967468Snon 186079697Snon ti->ti_quirks = ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS; 186179697Snon ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8; 186279697Snon ti->ti_flags_valid = SCSI_LOW_TARG_FLAGS_USER_VALID; 186379697Snon#ifdef SCSI_LOW_FLAGS_QUIRKS_OK 186479697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID; 186579697Snon#endif /* SCSI_LOW_FLAGS_QUIRKS_OK */ 186673025Snon 186779697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 186879697Snon { 186979697Snon (*slp->sl_funcs->scsi_low_targ_init) 187079697Snon (slp, ti, SCSI_LOW_INFO_ALLOC); 187179697Snon } 187279697Snon scsi_low_calcf_target(ti); 187367468Snon return ti; 187467468Snon} 187567468Snon 187667468Snonstatic void 187767468Snonscsi_low_free_ti(slp) 187867468Snon struct scsi_low_softc *slp; 187967468Snon{ 188067468Snon struct targ_info *ti, *tib; 188167468Snon struct lun_info *li, *nli; 188267468Snon 188371999Sphk for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib) 188467468Snon { 188567468Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli) 188667468Snon { 188779697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 188879697Snon { 188979697Snon (*slp->sl_funcs->scsi_low_lun_init) 189079697Snon (slp, ti, li, SCSI_LOW_INFO_DEALLOC); 189179697Snon } 189267468Snon nli = LIST_NEXT(li, lun_chain); 189379697Snon SCSI_LOW_FREE(li); 189467468Snon } 189579697Snon 189679697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 189779697Snon { 189879697Snon (*slp->sl_funcs->scsi_low_targ_init) 189979697Snon (slp, ti, SCSI_LOW_INFO_DEALLOC); 190079697Snon } 190179697Snon tib = TAILQ_NEXT(ti, ti_chain); 190279697Snon SCSI_LOW_FREE(ti); 190367468Snon } 190467468Snon} 190567468Snon 190667468Snon/************************************************************** 190767468Snon * timeout 190867468Snon **************************************************************/ 190967468Snonvoid 191079697Snonscsi_low_bus_idle(slp) 191179697Snon struct scsi_low_softc *slp; 191279697Snon{ 191379697Snon 191479697Snon slp->sl_retry_sel = 0; 191579697Snon if (slp->sl_Tnexus == NULL) 191679697Snon scsi_low_start(slp); 191779697Snon} 191879697Snon 191979697Snonstatic void 192067468Snonscsi_low_timeout(arg) 192167468Snon void *arg; 192267468Snon{ 192367468Snon struct scsi_low_softc *slp = arg; 192479697Snon int s; 192579697Snon 192679697Snon s = SCSI_LOW_SPLSCSI(); 192779697Snon (void) scsi_low_timeout_check(slp); 192879697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 192979697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 193079697Snon splx(s); 193179697Snon} 193279697Snon 193379697Snonstatic int 193479697Snonscsi_low_timeout_check(slp) 193579697Snon struct scsi_low_softc *slp; 193679697Snon{ 193767468Snon struct targ_info *ti; 193879697Snon struct lun_info *li; 193967468Snon struct slccb *cb = NULL; /* XXX */ 194067468Snon 194179697Snon /* selection restart */ 194279697Snon if (slp->sl_retry_sel != 0) 194367468Snon { 194479697Snon slp->sl_retry_sel = 0; 194579697Snon if (slp->sl_Tnexus != NULL) 194679697Snon goto step1; 194767468Snon 194879697Snon cb = TAILQ_FIRST(&slp->sl_start); 194979697Snon if (cb == NULL) 195079697Snon goto step1; 195179697Snon 195279697Snon if (cb->ccb_selrcnt >= SCSI_LOW_MAX_SELECTION_RETRY) 195367468Snon { 195479697Snon cb->ccb_flags |= CCB_NORETRY; 195579697Snon cb->ccb_error |= SELTIMEOUTIO; 195679697Snon if (scsi_low_revoke_ccb(slp, cb, 1) != NULL) 195779697Snon panic("%s: ccb not finished\n", slp->sl_xname); 195867468Snon } 195979697Snon 196079697Snon if (slp->sl_Tnexus == NULL) 196179697Snon scsi_low_start(slp); 196267468Snon } 196379697Snon 196479697Snon /* call hardware timeout */ 196579697Snonstep1: 196679697Snon if (slp->sl_funcs->scsi_low_timeout != NULL) 196767468Snon { 196879697Snon (*slp->sl_funcs->scsi_low_timeout) (slp); 196979697Snon } 197079697Snon 197179697Snon if (slp->sl_timeout_count ++ < 197279697Snon SCSI_LOW_TIMEOUT_CHECK_INTERVAL * SCSI_LOW_TIMEOUT_HZ) 197379697Snon return 0; 197479697Snon 197579697Snon slp->sl_timeout_count = 0; 197679697Snon if (slp->sl_nio > 0) 197779697Snon { 197879697Snon if ((cb = slp->sl_Qnexus) != NULL) 197967468Snon { 198067468Snon cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 198167468Snon if (cb->ccb_tc < 0) 198267468Snon goto bus_reset; 198367468Snon } 198479697Snon else if (slp->sl_disc == 0) 198567468Snon { 198679697Snon if ((cb = TAILQ_FIRST(&slp->sl_start)) == NULL) 198779697Snon return 0; 198867468Snon 198979697Snon cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 199079697Snon if (cb->ccb_tc < 0) 199179697Snon goto bus_reset; 199279697Snon } 199379697Snon else for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 199479697Snon ti = TAILQ_NEXT(ti, ti_chain)) 199579697Snon { 199679697Snon if (ti->ti_disc == 0) 199779697Snon continue; 199867468Snon 199979697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 200079697Snon li = LIST_NEXT(li, lun_chain)) 200167468Snon { 200279697Snon for (cb = TAILQ_FIRST(&li->li_discq); 200379697Snon cb != NULL; 200479697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 200579697Snon { 200679697Snon cb->ccb_tc -= 200779697Snon SCSI_LOW_TIMEOUT_CHECK_INTERVAL; 200879697Snon if (cb->ccb_tc < 0) 200979697Snon goto bus_reset; 201079697Snon } 201167468Snon } 201267468Snon } 201379697Snon 201467468Snon } 201579697Snon else if ((slp->sl_flags & HW_POWERCTRL) != 0) 201679697Snon { 201779697Snon if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0) 201879697Snon return 0; 201967468Snon 202079697Snon if (slp->sl_active != 0) 202179697Snon { 202279697Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 202379697Snon slp->sl_active = 0; 202479697Snon return 0; 202579697Snon } 202667468Snon 202779697Snon slp->sl_powc --; 202879697Snon if (slp->sl_powc < 0) 202979697Snon { 203079697Snon slp->sl_powc = SCSI_LOW_POWDOWN_TC; 203179697Snon slp->sl_flags |= HW_POWDOWN; 203279697Snon (*slp->sl_funcs->scsi_low_power) 203379697Snon (slp, SCSI_LOW_POWDOWN); 203479697Snon } 203579697Snon } 203679697Snon return 0; 203767468Snon 203867468Snonbus_reset: 203967468Snon cb->ccb_error |= TIMEOUTIO; 204079697Snon printf("%s: slccb (0x%lx) timeout!\n", slp->sl_xname, (u_long) cb); 204167468Snon scsi_low_info(slp, NULL, "scsi bus hangup. try to recover."); 204267468Snon scsi_low_init(slp, SCSI_LOW_RESTART_HARD); 204367468Snon scsi_low_start(slp); 204479697Snon return ERESTART; 204567468Snon} 204667468Snon 204767468Snon 204879697Snonstatic int 204979697Snonscsi_low_abort_ccb(slp, cb) 205079697Snon struct scsi_low_softc *slp; 205179697Snon struct slccb *cb; 205279697Snon{ 205379697Snon struct targ_info *ti; 205479697Snon struct lun_info *li; 205579697Snon u_int msg; 205667468Snon 205779697Snon if (cb == NULL) 205879697Snon return EINVAL; 205979697Snon if ((cb->ccb_omsgoutflag & 206079697Snon (SCSI_LOW_MSG_ABORT | SCSI_LOW_MSG_ABORT_QTAG)) != 0) 206179697Snon return EBUSY; 206267468Snon 206379697Snon ti = cb->ti; 206479697Snon li = cb->li; 206579697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 206679697Snon msg = SCSI_LOW_MSG_ABORT; 206779697Snon else 206879697Snon msg = SCSI_LOW_MSG_ABORT_QTAG; 206967468Snon 207079697Snon cb->ccb_error |= ABORTIO; 207179697Snon cb->ccb_flags |= CCB_NORETRY; 207279697Snon scsi_low_ccb_message_assert(cb, msg); 207367468Snon 207479697Snon if (cb == slp->sl_Qnexus) 207579697Snon { 207679697Snon scsi_low_assert_msg(slp, ti, msg, 1); 207779697Snon } 207879697Snon else if ((cb->ccb_flags & CCB_DISCQ) != 0) 207979697Snon { 208079697Snon if (scsi_low_revoke_ccb(slp, cb, 0) == NULL) 208179697Snon panic("%s: revoked ccb done\n", slp->sl_xname); 208267468Snon 208379697Snon cb->ccb_flags |= CCB_STARTQ; 208479697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 208567468Snon 208679697Snon if (slp->sl_Tnexus == NULL) 208779697Snon scsi_low_start(slp); 208879697Snon } 208979697Snon else 209079697Snon { 209179697Snon if (scsi_low_revoke_ccb(slp, cb, 1) != NULL) 209279697Snon panic("%s: revoked ccb retried\n", slp->sl_xname); 209379697Snon } 209479697Snon return 0; 209567468Snon} 209667468Snon 209779697Snon/************************************************************** 209879697Snon * Generic SCSI INTERFACE 209979697Snon **************************************************************/ 210067468Snonint 210179697Snonscsi_low_attach(slp, openings, ntargs, nluns, targsize, lunsize) 210267468Snon struct scsi_low_softc *slp; 210379697Snon int openings, ntargs, nluns, targsize, lunsize; 210467468Snon{ 210567468Snon struct targ_info *ti; 210667468Snon struct lun_info *li; 210779697Snon int s, i, nccb, rv; 210867468Snon 210979697Snon#ifdef SCSI_LOW_INTERFACE_XS 211079697Snon slp->sl_osdep_fp = &scsi_low_osdep_funcs_xs; 211179697Snon#endif /* SCSI_LOW_INTERFACE_XS */ 211279697Snon#ifdef SCSI_LOW_INTERFACE_CAM 211379697Snon slp->sl_osdep_fp = &scsi_low_osdep_funcs_cam; 211479697Snon#endif /* SCSI_LOW_INTERFACE_CAM */ 211579697Snon 211679697Snon if (slp->sl_osdep_fp == NULL) 211779697Snon panic("scsi_low: interface not spcified\n"); 211879697Snon 211967468Snon if (ntargs > SCSI_LOW_NTARGETS) 212067468Snon { 212167468Snon printf("scsi_low: %d targets are too large\n", ntargs); 212267468Snon printf("change kernel options SCSI_LOW_NTARGETS"); 212379697Snon return EINVAL; 212467468Snon } 212567468Snon 212679697Snon if (openings <= 0) 212779697Snon slp->sl_openings = (SCSI_LOW_NCCB / ntargs); 212879697Snon else 212979697Snon slp->sl_openings = openings; 213079697Snon slp->sl_ntargs = ntargs; 213179697Snon slp->sl_nluns = nluns; 213279697Snon slp->sl_max_retry = SCSI_LOW_MAX_RETRY; 213367468Snon 213479697Snon if (lunsize < sizeof(struct lun_info)) 213579697Snon lunsize = sizeof(struct lun_info); 213679697Snon 213779697Snon if (targsize < sizeof(struct targ_info)) 213879697Snon targsize = sizeof(struct targ_info); 213979697Snon 214079697Snon slp->sl_targsize = targsize; 214167468Snon for (i = 0; i < ntargs; i ++) 214267468Snon { 214379697Snon ti = scsi_low_alloc_ti(slp, i); 214479697Snon ti->ti_lunsize = lunsize; 214567468Snon li = scsi_low_alloc_li(ti, 0, 1); 214667468Snon } 214767468Snon 214867468Snon /* initialize queue */ 214979697Snon nccb = openings * ntargs; 215067468Snon if (nccb >= SCSI_LOW_NCCB || nccb <= 0) 215167468Snon nccb = SCSI_LOW_NCCB; 215267468Snon scsi_low_init_ccbque(nccb); 215367468Snon TAILQ_INIT(&slp->sl_start); 215467468Snon 215579697Snon /* call os depend attach */ 215679697Snon s = SCSI_LOW_SPLSCSI(); 215779697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_attach) (slp); 215879697Snon if (rv != 0) 215979697Snon { 216079697Snon splx(s); 216179697Snon printf("%s: scsi_low_attach: osdep attach failed\n", 216279697Snon slp->sl_xname); 216379697Snon return EINVAL; 216479697Snon } 216567468Snon 216679697Snon /* check hardware */ 216779697Snon SCSI_LOW_DELAY(1000); /* wait for 1ms */ 216879697Snon if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0) 216979697Snon { 217079697Snon splx(s); 217179697Snon printf("%s: scsi_low_attach: initialization failed\n", 217279697Snon slp->sl_xname); 217379697Snon return EINVAL; 217479697Snon } 217567468Snon 217667468Snon /* start watch dog */ 217779697Snon slp->sl_timeout_count = 0; 217879697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 217979697Snon (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START); 218079697Snon LIST_INSERT_HEAD(&sl_tab, slp, sl_chain); 218167468Snon 218279697Snon /* fake call */ 218379697Snon scsi_low_abort_ccb(slp, scsi_low_find_ccb(slp, 0, 0, NULL)); 218467468Snon 218579697Snon#ifdef SCSI_LOW_START_UP_CHECK 218679697Snon /* probing devices */ 218779697Snon scsi_low_start_up(slp); 218879697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 218967468Snon 219079697Snon /* call os depend attach done*/ 219179697Snon (*slp->sl_osdep_fp->scsi_low_osdep_world_start) (slp); 219279697Snon splx(s); 219379697Snon return 0; 219467468Snon} 219567468Snon 219667468Snonint 219767468Snonscsi_low_dettach(slp) 219867468Snon struct scsi_low_softc *slp; 219967468Snon{ 220079697Snon int s, rv; 220167468Snon 220279697Snon s = SCSI_LOW_SPLSCSI(); 220379697Snon if (scsi_low_is_busy(slp) != 0) 220479697Snon { 220579697Snon splx(s); 220667468Snon return EBUSY; 220779697Snon } 220867468Snon 220979697Snon scsi_low_deactivate(slp); 221067468Snon 221179697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_dettach) (slp); 221279697Snon if (rv != 0) 221379697Snon { 221479697Snon splx(s); 221579697Snon return EBUSY; 221679697Snon } 221767468Snon 221867468Snon scsi_low_free_ti(slp); 221979697Snon LIST_REMOVE(slp, sl_chain); 222079697Snon splx(s); 222167468Snon return 0; 222267468Snon} 222367468Snon 222479697Snon/************************************************************** 222579697Snon * Generic enqueue 222679697Snon **************************************************************/ 222779697Snonstatic int 222879697Snonscsi_low_enqueue(slp, ti, li, cb, flags, msg) 222979697Snon struct scsi_low_softc *slp; 223067468Snon struct targ_info *ti; 223167468Snon struct lun_info *li; 223267468Snon struct slccb *cb; 223379697Snon u_int flags, msg; 223479697Snon{ 223567468Snon 223679697Snon cb->ti = ti; 223779697Snon cb->li = li; 223867468Snon 223979697Snon scsi_low_ccb_message_assert(cb, msg); 224067468Snon 224179697Snon cb->ccb_otag = cb->ccb_tag = SCSI_LOW_UNKTAG; 224279697Snon scsi_low_alloc_qtag(cb); 224367468Snon 224479697Snon cb->ccb_flags = flags | CCB_STARTQ; 224579697Snon cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 224679697Snon cb->ccb_error |= PENDINGIO; 224779697Snon 224879697Snon if ((flags & CCB_URGENT) != 0) 224979697Snon { 225079697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 225179697Snon } 225279697Snon else 225379697Snon { 225467468Snon TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain); 225579697Snon } 225667468Snon 225779697Snon slp->sl_nio ++; 225867468Snon 225979697Snon if (slp->sl_Tnexus == NULL) 226079697Snon scsi_low_start(slp); 226179697Snon return 0; 226279697Snon} 226367468Snon 226479697Snonstatic int 226579697Snonscsi_low_message_enqueue(slp, ti, li, flags) 226679697Snon struct scsi_low_softc *slp; 226779697Snon struct targ_info *ti; 226879697Snon struct lun_info *li; 226979697Snon u_int flags; 227079697Snon{ 227179697Snon struct slccb *cb; 227279697Snon u_int tmsgflags; 227367468Snon 227479697Snon tmsgflags = ti->ti_setup_msg; 227579697Snon ti->ti_setup_msg = 0; 227667468Snon 227779697Snon flags |= CCB_NORETRY; 227879697Snon if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL) 227979697Snon return ENOMEM; 228067468Snon 228179697Snon cb->osdep = NULL; 228279697Snon cb->bp = NULL; 228379697Snon scsi_low_enqueue(slp, ti, li, cb, flags, tmsgflags); 228479697Snon return 0; 228579697Snon} 228667468Snon 228779697Snon/************************************************************** 228879697Snon * Generic Start & Done 228979697Snon **************************************************************/ 229079697Snon#define SLSC_MODE_SENSE_SHORT 0x1a 229179697Snonstatic u_int8_t ss_cmd[6] = {START_STOP, 0, 0, 0, SSS_START, 0}; 229279697Snonstatic u_int8_t sms_cmd[6] = {SLSC_MODE_SENSE_SHORT, 0x08, 0x0a, 0, 229379697Snon sizeof(struct scsi_low_mode_sense_data), 0}; 229479697Snonstatic u_int8_t inq_cmd[6] = {INQUIRY, 0, 0, 0, 229579697Snon sizeof(struct scsi_low_inq_data), 0}; 229679697Snonstatic u_int8_t unit_ready_cmd[6]; 229792770Salfredstatic int scsi_low_setup_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *); 229892770Salfredstatic int scsi_low_sense_abort_start(struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *); 229992770Salfredstatic int scsi_low_resume(struct scsi_low_softc *); 230079697Snon 230179697Snonstatic void 230279697Snonscsi_low_unit_ready_cmd(cb) 230379697Snon struct slccb *cb; 230479697Snon{ 230579697Snon 230679697Snon cb->ccb_scp.scp_cmd = unit_ready_cmd; 230779697Snon cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd); 230879697Snon cb->ccb_scp.scp_datalen = 0; 230979697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 231079697Snon cb->ccb_tcmax = 15; 231167468Snon} 231279697Snon 231367468Snonstatic int 231479697Snonscsi_low_sense_abort_start(slp, ti, li, cb) 231579697Snon struct scsi_low_softc *slp; 231667468Snon struct targ_info *ti; 231779697Snon struct lun_info *li; 231867468Snon struct slccb *cb; 231979697Snon{ 232067468Snon 232179697Snon cb->ccb_scp.scp_cmdlen = 6; 232279697Snon SCSI_LOW_BZERO(cb->ccb_scsi_cmd, cb->ccb_scp.scp_cmdlen); 232379697Snon cb->ccb_scsi_cmd[0] = REQUEST_SENSE; 232479697Snon cb->ccb_scsi_cmd[4] = sizeof(cb->ccb_sense); 232579697Snon cb->ccb_scp.scp_cmd = cb->ccb_scsi_cmd; 232679697Snon cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense; 232779697Snon cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense); 232879697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 232979697Snon cb->ccb_tcmax = 15; 233079697Snon scsi_low_ccb_message_clear(cb); 233179697Snon if ((cb->ccb_flags & CCB_CLEARQ) != 0) 233267468Snon { 233379697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 233467468Snon } 233579697Snon else 233679697Snon { 233779697Snon SCSI_LOW_BZERO(&cb->ccb_sense, sizeof(cb->ccb_sense)); 233879697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 233979697Snon scsi_low_assert_msg(slp, ti, ti->ti_setup_msg_done, 0); 234079697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 234179697Snon } 234267468Snon 234379697Snon return SCSI_LOW_START_NO_QTAG; 234479697Snon} 234567468Snon 234679697Snonstatic int 234779697Snonscsi_low_setup_start(slp, ti, li, cb) 234879697Snon struct scsi_low_softc *slp; 234979697Snon struct targ_info *ti; 235079697Snon struct lun_info *li; 235179697Snon struct slccb *cb; 235279697Snon{ 235367468Snon 235479697Snon switch(li->li_state) 235579697Snon { 235679697Snon case SCSI_LOW_LUN_SLEEP: 235779697Snon scsi_low_unit_ready_cmd(cb); 235879697Snon break; 235967468Snon 236079697Snon case SCSI_LOW_LUN_START: 236179697Snon cb->ccb_scp.scp_cmd = ss_cmd; 236279697Snon cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd); 236379697Snon cb->ccb_scp.scp_datalen = 0; 236479697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 236579697Snon cb->ccb_tcmax = 30; 236679697Snon break; 236767468Snon 236879697Snon case SCSI_LOW_LUN_INQ: 236979697Snon cb->ccb_scp.scp_cmd = inq_cmd; 237079697Snon cb->ccb_scp.scp_cmdlen = sizeof(inq_cmd); 237179697Snon cb->ccb_scp.scp_data = (u_int8_t *)&li->li_inq; 237279697Snon cb->ccb_scp.scp_datalen = sizeof(li->li_inq); 237379697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 237479697Snon cb->ccb_tcmax = 15; 237579697Snon break; 237667468Snon 237779697Snon case SCSI_LOW_LUN_MODEQ: 237879697Snon cb->ccb_scp.scp_cmd = sms_cmd; 237979697Snon cb->ccb_scp.scp_cmdlen = sizeof(sms_cmd); 238079697Snon cb->ccb_scp.scp_data = (u_int8_t *)&li->li_sms; 238179697Snon cb->ccb_scp.scp_datalen = sizeof(li->li_sms); 238279697Snon cb->ccb_scp.scp_direction = SCSI_LOW_READ; 238379697Snon cb->ccb_tcmax = 15; 238479697Snon return SCSI_LOW_START_QTAG; 238567468Snon 238679697Snon default: 238779697Snon panic("%s: no setup phase\n", slp->sl_xname); 238867468Snon } 238967468Snon 239079697Snon return SCSI_LOW_START_NO_QTAG; 239167468Snon} 239267468Snon 239379697Snonstatic int 239479697Snonscsi_low_resume(slp) 239579697Snon struct scsi_low_softc *slp; 239667468Snon{ 239767468Snon 239879697Snon if (slp->sl_flags & HW_RESUME) 239979697Snon return EJUSTRETURN; 240079697Snon slp->sl_flags &= ~HW_POWDOWN; 240179697Snon if (slp->sl_funcs->scsi_low_power != NULL) 240279697Snon { 240379697Snon slp->sl_flags |= HW_RESUME; 240479697Snon slp->sl_rstep = 0; 240579697Snon (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); 240679697Snon (*slp->sl_osdep_fp->scsi_low_osdep_timeout) 240779697Snon (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, 240879697Snon SCSI_LOW_TIMEOUT_START); 240979697Snon return EJUSTRETURN; 241079697Snon } 241179697Snon return 0; 241267468Snon} 241367468Snon 241467468Snonstatic void 241567468Snonscsi_low_start(slp) 241667468Snon struct scsi_low_softc *slp; 241767468Snon{ 241867468Snon struct targ_info *ti; 241967468Snon struct lun_info *li; 242067468Snon struct slccb *cb; 242167468Snon int rv; 242267468Snon 242379697Snon /* check hardware exists or under initializations ? */ 242479697Snon if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0) 242567468Snon return; 242667468Snon 242767468Snon /* check hardware power up ? */ 242867468Snon if ((slp->sl_flags & HW_POWERCTRL) != 0) 242967468Snon { 243067468Snon slp->sl_active ++; 243167468Snon if (slp->sl_flags & (HW_POWDOWN | HW_RESUME)) 243267468Snon { 243379697Snon if (scsi_low_resume(slp) == EJUSTRETURN) 243467468Snon return; 243567468Snon } 243667468Snon } 243767468Snon 243867468Snon /* setup nexus */ 243967468Snon#ifdef SCSI_LOW_DIAGNOSTIC 244079697Snon if (slp->sl_Tnexus || slp->sl_Lnexus || slp->sl_Qnexus) 244167468Snon { 244267468Snon scsi_low_info(slp, NULL, "NEXUS INCOSISTENT"); 244379697Snon panic("%s: inconsistent\n", slp->sl_xname); 244467468Snon } 244567468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 244667468Snon 244779697Snon for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL; 244879697Snon cb = TAILQ_NEXT(cb, ccb_chain)) 244967468Snon { 245067468Snon li = cb->li; 245179697Snon 245279697Snon if (li->li_disc == 0) 245379697Snon { 245467468Snon goto scsi_low_cmd_start; 245579697Snon } 245679697Snon else if (li->li_nqio > 0) 245779697Snon { 245879697Snon if (li->li_nqio < li->li_maxnqio || 245979697Snon (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 246079697Snon goto scsi_low_cmd_start; 246179697Snon } 246267468Snon } 246367468Snon return; 246467468Snon 246567468Snonscsi_low_cmd_start: 246679697Snon cb->ccb_flags &= ~CCB_STARTQ; 246779697Snon TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); 246879697Snon ti = cb->ti; 246967468Snon 247067468Snon /* clear all error flag bits (for restart) */ 247167468Snon cb->ccb_error = 0; 247279697Snon cb->ccb_datalen = -1; 247379697Snon cb->ccb_scp.scp_status = ST_UNKNOWN; 247467468Snon 247567468Snon /* setup nexus pointer */ 247679697Snon slp->sl_Qnexus = cb; 247779697Snon slp->sl_Lnexus = li; 247879697Snon slp->sl_Tnexus = ti; 247967468Snon 248067468Snon /* initialize msgsys */ 248167468Snon scsi_low_init_msgsys(slp, ti); 248267468Snon 248379697Snon /* exec cmd */ 248479697Snon if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 248567468Snon { 248679697Snon /* CA state or forced abort */ 248779697Snon rv = scsi_low_sense_abort_start(slp, ti, li, cb); 248867468Snon } 248979697Snon else if (li->li_state >= SCSI_LOW_LUN_OK) 249067468Snon { 249179697Snon cb->ccb_flags &= ~CCB_INTERNAL; 249279697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, cb); 249379697Snon if (cb->ccb_msgoutflag != 0) 249479697Snon { 249579697Snon scsi_low_ccb_message_exec(slp, cb); 249679697Snon } 249767468Snon } 249879697Snon else 249967468Snon { 250079697Snon cb->ccb_flags |= CCB_INTERNAL; 250179697Snon rv = scsi_low_setup_start(slp, ti, li, cb); 250279697Snon } 250367468Snon 250479697Snon /* allocate qtag */ 250579697Snon#define SCSI_LOW_QTAG_OK (SCSI_LOW_QTAG | SCSI_LOW_DISC) 250667468Snon 250779697Snon if (rv == SCSI_LOW_START_QTAG && 250879697Snon (li->li_flags & SCSI_LOW_QTAG_OK) == SCSI_LOW_QTAG_OK && 250979697Snon li->li_maxnqio > 0) 251079697Snon { 251179697Snon u_int qmsg; 251267468Snon 251379697Snon scsi_low_activate_qtag(cb); 251479697Snon if ((scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 251579697Snon SCSI_LOW_CMD_ORDERED_QTAG) != 0) 251679697Snon qmsg = SCSI_LOW_MSG_ORDERED_QTAG; 251779697Snon else if ((cb->ccb_flags & CCB_URGENT) != 0) 251879697Snon qmsg = SCSI_LOW_MSG_HEAD_QTAG; 251979697Snon else 252079697Snon qmsg = SCSI_LOW_MSG_SIMPLE_QTAG; 252179697Snon scsi_low_assert_msg(slp, ti, qmsg, 0); 252267468Snon } 252367468Snon 252467468Snon /* timeout */ 252567468Snon if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT) 252667468Snon cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 252767468Snon cb->ccb_tc = cb->ccb_tcmax; 252867468Snon 252967468Snon /* setup saved scsi data pointer */ 253067468Snon cb->ccb_sscp = cb->ccb_scp; 253167468Snon 253267468Snon /* setup current scsi pointer */ 253367468Snon slp->sl_scp = cb->ccb_sscp; 253467468Snon slp->sl_error = cb->ccb_error; 253567468Snon 253679697Snon /* assert always an identify msg */ 253779697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); 253879697Snon 253979697Snon /* debug section */ 254079697Snon#ifdef SCSI_LOW_DIAGNOSTIC 254179697Snon scsi_low_msg_log_init(&ti->ti_log_msgin); 254279697Snon scsi_low_msg_log_init(&ti->ti_log_msgout); 254379697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 254479697Snon 254567468Snon /* selection start */ 254679697Snon slp->sl_selid = cb; 254767468Snon rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb)); 254867468Snon if (rv == SCSI_LOW_START_OK) 254967468Snon { 255067468Snon#ifdef SCSI_LOW_STATICS 255167468Snon scsi_low_statics.nexus_win ++; 255267468Snon#endif /* SCSI_LOW_STATICS */ 255367468Snon return; 255467468Snon } 255567468Snon 255679697Snon scsi_low_arbit_fail(slp, cb); 255767468Snon#ifdef SCSI_LOW_STATICS 255867468Snon scsi_low_statics.nexus_fail ++; 255967468Snon#endif /* SCSI_LOW_STATICS */ 256067468Snon} 256167468Snon 256267468Snonvoid 256379697Snonscsi_low_arbit_fail(slp, cb) 256467468Snon struct scsi_low_softc *slp; 256579697Snon struct slccb *cb; 256679697Snon{ 256779697Snon struct targ_info *ti = cb->ti; 256879697Snon 256979697Snon scsi_low_deactivate_qtag(cb); 257079697Snon scsi_low_ccb_message_retry(cb); 257179697Snon cb->ccb_flags |= CCB_STARTQ; 257279697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 257379697Snon 257479697Snon scsi_low_bus_release(slp, ti); 257579697Snon 257679697Snon cb->ccb_selrcnt ++; 257779697Snon if (slp->sl_disc == 0) 257879697Snon { 257979697Snon#ifdef SCSI_LOW_DIAGNOSTIC 258079697Snon printf("%s: try selection again\n", slp->sl_xname); 258179697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 258279697Snon slp->sl_retry_sel = 1; 258379697Snon } 258479697Snon} 258579697Snon 258679697Snonstatic void 258779697Snonscsi_low_bus_release(slp, ti) 258879697Snon struct scsi_low_softc *slp; 258967468Snon struct targ_info *ti; 259067468Snon{ 259167468Snon 259279697Snon if (ti->ti_disc > 0) 259379697Snon { 259479697Snon SCSI_LOW_SETUP_PHASE(ti, PH_DISC); 259579697Snon } 259679697Snon else 259779697Snon { 259879697Snon SCSI_LOW_SETUP_PHASE(ti, PH_NULL); 259979697Snon } 260079697Snon 260167468Snon /* clear all nexus pointer */ 260279697Snon slp->sl_Qnexus = NULL; 260379697Snon slp->sl_Lnexus = NULL; 260479697Snon slp->sl_Tnexus = NULL; 260567468Snon 260667468Snon /* clear selection assert */ 260767468Snon slp->sl_selid = NULL; 260867468Snon 260967468Snon /* clear nexus data */ 261067468Snon slp->sl_scp.scp_direction = SCSI_LOW_RWUNK; 261179697Snon 261279697Snon /* clear phase change counter */ 261379697Snon slp->sl_ph_count = 0; 261467468Snon} 261567468Snon 261667468Snonstatic int 261779697Snonscsi_low_setup_done(slp, cb) 261867468Snon struct scsi_low_softc *slp; 261967468Snon struct slccb *cb; 262067468Snon{ 262167468Snon struct targ_info *ti; 262267468Snon struct lun_info *li; 262367468Snon 262467468Snon ti = cb->ti; 262567468Snon li = cb->li; 262679697Snon 262779697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 262867468Snon { 262979697Snon cb->ccb_error |= ABORTIO; 263079697Snon return SCSI_LOW_DONE_COMPLETE; 263179697Snon } 263279697Snon 263379697Snon /* XXX: special huck for selection timeout */ 263479697Snon if (li->li_state == SCSI_LOW_LUN_SLEEP && 263579697Snon (cb->ccb_error & SELTIMEOUTIO) != 0) 263679697Snon { 263779697Snon cb->ccb_error |= ABORTIO; 263879697Snon return SCSI_LOW_DONE_COMPLETE; 263979697Snon } 264079697Snon 264179697Snon switch(li->li_state) 264279697Snon { 264379697Snon case SCSI_LOW_LUN_INQ: 264479697Snon if (cb->ccb_error != 0) 264567468Snon { 264679697Snon li->li_diskflags &= 264779697Snon ~(SCSI_LOW_DISK_LINK | SCSI_LOW_DISK_QTAG); 264879697Snon if (li->li_lun > 0) 264979697Snon goto resume; 265079697Snon ti->ti_diskflags &= 265179697Snon ~(SCSI_LOW_DISK_SYNC | SCSI_LOW_DISK_WIDE); 265267468Snon } 265379697Snon else if ((li->li_inq.sd_version & 7) >= 2 || 265479697Snon (li->li_inq.sd_len >= 4)) 265567468Snon { 265679697Snon if ((li->li_inq.sd_support & 0x2) == 0) 265779697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 265879697Snon if ((li->li_inq.sd_support & 0x8) == 0) 265979697Snon li->li_diskflags &= ~SCSI_LOW_DISK_LINK; 266079697Snon if (li->li_lun > 0) 266179697Snon goto resume; 266279697Snon if ((li->li_inq.sd_support & 0x10) == 0) 266379697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_SYNC; 266479697Snon if ((li->li_inq.sd_support & 0x20) == 0) 266579697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_16; 266679697Snon if ((li->li_inq.sd_support & 0x40) == 0) 266779697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_32; 266879697Snon } 266979697Snon else 267079697Snon { 267179697Snon li->li_diskflags &= 267279697Snon ~(SCSI_LOW_DISK_QTAG | SCSI_LOW_DISK_LINK); 267379697Snon if (li->li_lun > 0) 267479697Snon goto resume; 267579697Snon ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE; 267679697Snon } 267779697Snon ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_DISK_VALID; 267879697Snonresume: 267979697Snon scsi_low_calcf_target(ti); 268079697Snon scsi_low_calcf_lun(li); 268179697Snon break; 268279697Snon 268379697Snon case SCSI_LOW_LUN_MODEQ: 268479697Snon if (cb->ccb_error != 0) 268579697Snon { 268679697Snon if (cb->ccb_error & SENSEIO) 268767468Snon { 268879697Snon#ifdef SCSI_LOW_DEBUG 268979697Snon if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE) 269079697Snon { 269179697Snon printf("SENSE: [%x][%x][%x][%x][%x]\n", 269279697Snon (u_int) cb->ccb_sense.error_code, 269379697Snon (u_int) cb->ccb_sense.segment, 269479697Snon (u_int) cb->ccb_sense.flags, 269579697Snon (u_int) cb->ccb_sense.add_sense_code, 269679697Snon (u_int) cb->ccb_sense.add_sense_code_qual); 269779697Snon } 269879697Snon#endif /* SCSI_LOW_DEBUG */ 269967468Snon } 270079697Snon else 270179697Snon { 270279697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 270379697Snon } 270479697Snon } 270579697Snon else if ((li->li_sms.sms_cmp.cmp_page & 0x3f) == 0x0a) 270679697Snon { 270779697Snon if (li->li_sms.sms_cmp.cmp_qc & 0x02) 270879697Snon li->li_qflags |= SCSI_LOW_QFLAG_CA_QCLEAR; 270979697Snon else 271079697Snon li->li_qflags &= ~SCSI_LOW_QFLAG_CA_QCLEAR; 271179697Snon if ((li->li_sms.sms_cmp.cmp_qc & 0x01) != 0) 271279697Snon li->li_diskflags &= ~SCSI_LOW_DISK_QTAG; 271379697Snon } 271479697Snon li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_DISK_VALID; 271579697Snon scsi_low_calcf_lun(li); 271679697Snon break; 271767468Snon 271879697Snon default: 271979697Snon break; 272079697Snon } 272179697Snon 272279697Snon li->li_state ++; 272379697Snon if (li->li_state == SCSI_LOW_LUN_OK) 272479697Snon { 272579697Snon scsi_low_calcf_target(ti); 272679697Snon scsi_low_calcf_lun(li); 272779697Snon if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID && 272879697Snon (slp->sl_show_result & SHOW_CALCF_RES) != 0) 272979697Snon { 273079697Snon scsi_low_calcf_show(li); 273179697Snon } 273279697Snon } 273379697Snon 273479697Snon cb->ccb_rcnt --; 273579697Snon return SCSI_LOW_DONE_RETRY; 273679697Snon} 273779697Snon 273879697Snonstatic int 273979697Snonscsi_low_done(slp, cb) 274079697Snon struct scsi_low_softc *slp; 274179697Snon struct slccb *cb; 274279697Snon{ 274379697Snon int rv; 274479697Snon 274579697Snon if (cb->ccb_error == 0) 274679697Snon { 274779697Snon if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0) 274879697Snon { 274979697Snon#ifdef SCSI_LOW_QCLEAR_AFTER_CA 275079697Snon /* XXX: 275179697Snon * SCSI-2 draft suggests 275279697Snon * page 0x0a QErr bit determins if 275379697Snon * the target aborts or continues 275479697Snon * the queueing io's after CA state resolved. 275579697Snon * However many targets seem not to support 275679697Snon * the page 0x0a. Thus we should manually clear the 275779697Snon * queuing io's after CA state. 275879697Snon */ 275979697Snon if ((cb->ccb_flags & CCB_CLEARQ) == 0) 276067468Snon { 276179697Snon cb->ccb_rcnt --; 276279697Snon cb->ccb_flags |= CCB_CLEARQ; 276379697Snon goto retry; 276479697Snon } 276579697Snon#endif /* SCSI_LOW_QCLEAR_AFTER_CA */ 276679697Snon 276779697Snon if ((cb->ccb_flags & CCB_SENSE) != 0) 276879697Snon cb->ccb_error |= (SENSEIO | ABORTIO); 276979697Snon cb->ccb_flags &= ~(CCB_SENSE | CCB_CLEARQ); 277079697Snon } 277179697Snon else switch (cb->ccb_sscp.scp_status) 277279697Snon { 277379697Snon case ST_GOOD: 277479697Snon case ST_MET: 277579697Snon case ST_INTERGOOD: 277679697Snon case ST_INTERMET: 277779697Snon if (cb->ccb_datalen == 0 || 277879697Snon cb->ccb_scp.scp_datalen == 0) 277967468Snon break; 278067468Snon 278179697Snon if (cb->ccb_scp.scp_cmdlen > 0 && 278279697Snon (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] & 278379697Snon SCSI_LOW_CMD_RESIDUAL_CHK) == 0) 278479697Snon break; 278579697Snon 278667468Snon cb->ccb_error |= PDMAERR; 278767468Snon break; 278867468Snon 278979697Snon case ST_BUSY: 279079697Snon case ST_QUEFULL: 279179697Snon cb->ccb_error |= (BUSYERR | STATERR); 279279697Snon break; 279379697Snon 279479697Snon case ST_CONFLICT: 279579697Snon cb->ccb_error |= (STATERR | ABORTIO); 279679697Snon break; 279779697Snon 279867468Snon case ST_CHKCOND: 279979697Snon case ST_CMDTERM: 280079697Snon if (cb->ccb_flags & (CCB_AUTOSENSE | CCB_INTERNAL)) 280179697Snon { 280279697Snon cb->ccb_rcnt --; 280373025Snon cb->ccb_flags |= CCB_SENSE; 280473025Snon goto retry; 280573025Snon } 280679697Snon cb->ccb_error |= (UACAERR | STATERR | ABORTIO); 280773025Snon break; 280867468Snon 280979697Snon case ST_UNKNOWN: 281067468Snon default: 281167468Snon cb->ccb_error |= FATALIO; 281267468Snon break; 281367468Snon } 281467468Snon } 281567468Snon else 281667468Snon { 281779697Snon if (cb->ccb_flags & CCB_SENSE) 281867468Snon { 281979697Snon cb->ccb_error |= (SENSEERR | ABORTIO); 282067468Snon } 282179697Snon cb->ccb_flags &= ~(CCB_CLEARQ | CCB_SENSE); 282279697Snon } 282367468Snon 282479697Snon /* internal ccb */ 282579697Snon if ((cb->ccb_flags & CCB_INTERNAL) != 0) 282679697Snon { 282779697Snon if (scsi_low_setup_done(slp, cb) == SCSI_LOW_DONE_RETRY) 282879697Snon goto retry; 282967468Snon } 283067468Snon 283179697Snon /* check a ccb msgout flag */ 283279697Snon if (cb->ccb_omsgoutflag != 0) 283367468Snon { 283479697Snon#define SCSI_LOW_MSG_ABORT_OK (SCSI_LOW_MSG_ABORT | \ 283579697Snon SCSI_LOW_MSG_ABORT_QTAG | \ 283679697Snon SCSI_LOW_MSG_CLEAR_QTAG | \ 283779697Snon SCSI_LOW_MSG_TERMIO) 283879697Snon 283979697Snon if ((cb->ccb_omsgoutflag & SCSI_LOW_MSG_ABORT_OK) != 0) 284067468Snon { 284179697Snon cb->ccb_error |= ABORTIO; 284267468Snon } 284367468Snon } 284467468Snon 284579697Snon /* call OS depend done */ 284679697Snon if (cb->osdep != NULL) 284767468Snon { 284879697Snon rv = (*slp->sl_osdep_fp->scsi_low_osdep_done) (slp, cb); 284979697Snon if (rv == EJUSTRETURN) 285079697Snon goto retry; 285167468Snon } 285279697Snon else if (cb->ccb_error != 0) 285367468Snon { 285479697Snon if (cb->ccb_rcnt >= slp->sl_max_retry) 285579697Snon cb->ccb_error |= ABORTIO; 285679697Snon 285779697Snon if ((cb->ccb_flags & CCB_NORETRY) == 0 && 285879697Snon (cb->ccb_error & ABORTIO) == 0) 285967468Snon goto retry; 286067468Snon } 286179697Snon 286279697Snon /* free our target */ 286379697Snon#ifdef SCSI_LOW_DEBUG 286479697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0) 286567468Snon { 286679697Snon printf(">> SCSI_LOW_DONE_COMPLETE ===============\n"); 286779697Snon scsi_low_print(slp, NULL); 286867468Snon } 286979697Snon#endif /* SCSI_LOW_DEBUG */ 287067468Snon 287179697Snon scsi_low_deactivate_qtag(cb); 287279697Snon scsi_low_dealloc_qtag(cb); 287367468Snon scsi_low_free_ccb(cb); 287479697Snon slp->sl_nio --; 287567468Snon return SCSI_LOW_DONE_COMPLETE; 287667468Snon 287767468Snonretry: 287879697Snon#ifdef SCSI_LOW_DEBUG 287979697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0) 288067468Snon { 288179697Snon printf("** SCSI_LOW_DONE_RETRY ===============\n"); 288279697Snon scsi_low_print(slp, NULL); 288367468Snon } 288479697Snon#endif /* SCSI_LOW_DEBUG */ 288579697Snon 288679697Snon cb->ccb_rcnt ++; 288779697Snon scsi_low_deactivate_qtag(cb); 288879697Snon scsi_low_ccb_message_retry(cb); 288967468Snon return SCSI_LOW_DONE_RETRY; 289067468Snon} 289167468Snon 289267468Snon/************************************************************** 289367468Snon * Reset 289467468Snon **************************************************************/ 289567468Snonstatic void 289679697Snonscsi_low_reset_nexus_target(slp, ti, fdone) 289779697Snon struct scsi_low_softc *slp; 289879697Snon struct targ_info *ti; 289979697Snon int fdone; 290067468Snon{ 290179697Snon struct lun_info *li; 290267468Snon 290379697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 290479697Snon li = LIST_NEXT(li, lun_chain)) 290579697Snon { 290679697Snon scsi_low_reset_nexus_lun(slp, li, fdone); 290779697Snon li->li_state = SCSI_LOW_LUN_SLEEP; 290879697Snon li->li_maxnqio = 0; 290979697Snon } 291079697Snon 291179697Snon ti->ti_disc = 0; 291279697Snon ti->ti_setup_msg = 0; 291379697Snon ti->ti_setup_msg_done = 0; 291479697Snon 291579697Snon ti->ti_osynch.offset = ti->ti_osynch.period = 0; 291679697Snon ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8; 291779697Snon 291879697Snon ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS; 291979697Snon ti->ti_flags_valid &= ~SCSI_LOW_TARG_FLAGS_DISK_VALID; 292079697Snon 292179697Snon if (slp->sl_funcs->scsi_low_targ_init != NULL) 292279697Snon { 292379697Snon ((*slp->sl_funcs->scsi_low_targ_init) 292479697Snon (slp, ti, SCSI_LOW_INFO_REVOKE)); 292579697Snon } 292679697Snon scsi_low_calcf_target(ti); 292779697Snon 292879697Snon for (li = LIST_FIRST(&ti->ti_litab); li != NULL; 292979697Snon li = LIST_NEXT(li, lun_chain)) 293079697Snon { 293179697Snon li->li_flags = 0; 293279697Snon 293379697Snon li->li_diskflags = SCSI_LOW_DISK_LFLAGS; 293479697Snon li->li_flags_valid &= ~SCSI_LOW_LUN_FLAGS_DISK_VALID; 293579697Snon 293679697Snon if (slp->sl_funcs->scsi_low_lun_init != NULL) 293779697Snon { 293879697Snon ((*slp->sl_funcs->scsi_low_lun_init) 293979697Snon (slp, ti, li, SCSI_LOW_INFO_REVOKE)); 294079697Snon } 294179697Snon scsi_low_calcf_lun(li); 294279697Snon } 294367468Snon} 294467468Snon 294567468Snonstatic void 294667468Snonscsi_low_reset_nexus(slp, fdone) 294767468Snon struct scsi_low_softc *slp; 294867468Snon int fdone; 294967468Snon{ 295067468Snon struct targ_info *ti; 295179697Snon struct slccb *cb, *topcb; 295267468Snon 295379697Snon if ((cb = slp->sl_Qnexus) != NULL) 295467468Snon { 295579697Snon topcb = scsi_low_revoke_ccb(slp, cb, fdone); 295667468Snon } 295779697Snon else 295879697Snon { 295979697Snon topcb = NULL; 296079697Snon } 296167468Snon 296279697Snon for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 296379697Snon ti = TAILQ_NEXT(ti, ti_chain)) 296467468Snon { 296579697Snon scsi_low_reset_nexus_target(slp, ti, fdone); 296679697Snon scsi_low_bus_release(slp, ti); 296767468Snon scsi_low_init_msgsys(slp, ti); 296867468Snon } 296967468Snon 297079697Snon if (topcb != NULL) 297179697Snon { 297279697Snon topcb->ccb_flags |= CCB_STARTQ; 297379697Snon TAILQ_INSERT_HEAD(&slp->sl_start, topcb, ccb_chain); 297479697Snon } 297579697Snon 297679697Snon slp->sl_disc = 0; 297779697Snon slp->sl_retry_sel = 0; 297867468Snon slp->sl_flags &= ~HW_PDMASTART; 297967468Snon} 298067468Snon 298167468Snon/* misc */ 298267468Snonstatic int tw_pos; 298367468Snonstatic char tw_chars[] = "|/-\\"; 298479697Snon#define TWIDDLEWAIT 10000 298567468Snon 298667468Snonstatic void 298767468Snonscsi_low_twiddle_wait(void) 298867468Snon{ 298967468Snon 299067468Snon cnputc('\b'); 299167468Snon cnputc(tw_chars[tw_pos++]); 299267468Snon tw_pos %= (sizeof(tw_chars) - 1); 299379697Snon SCSI_LOW_DELAY(TWIDDLEWAIT); 299467468Snon} 299567468Snon 299667468Snonvoid 299767468Snonscsi_low_bus_reset(slp) 299867468Snon struct scsi_low_softc *slp; 299967468Snon{ 300067468Snon int i; 300167468Snon 300267468Snon (*slp->sl_funcs->scsi_low_bus_reset) (slp); 300367468Snon 300467468Snon printf("%s: try to reset scsi bus ", slp->sl_xname); 300567468Snon for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++) 300667468Snon scsi_low_twiddle_wait(); 300767468Snon cnputc('\b'); 300867468Snon printf("\n"); 300967468Snon} 301067468Snon 301167468Snonint 301267468Snonscsi_low_restart(slp, flags, s) 301367468Snon struct scsi_low_softc *slp; 301467468Snon int flags; 301567468Snon u_char *s; 301667468Snon{ 301767468Snon int error; 301867468Snon 301967468Snon if (s != NULL) 302067468Snon printf("%s: scsi bus restart. reason: %s\n", slp->sl_xname, s); 302167468Snon 302267468Snon if ((error = scsi_low_init(slp, flags)) != 0) 302367468Snon return error; 302467468Snon 302567468Snon scsi_low_start(slp); 302667468Snon return 0; 302767468Snon} 302867468Snon 302967468Snon/************************************************************** 303067468Snon * disconnect and reselect 303167468Snon **************************************************************/ 303267468Snon#define MSGCMD_LUN(msg) (msg & 0x07) 303367468Snon 303467468Snonstatic struct slccb * 303567468Snonscsi_low_establish_ccb(ti, li, tag) 303667468Snon struct targ_info *ti; 303767468Snon struct lun_info *li; 303867468Snon scsi_low_tag_t tag; 303967468Snon{ 304067468Snon struct scsi_low_softc *slp = ti->ti_sc; 304167468Snon struct slccb *cb; 304267468Snon 304379697Snon if (li == NULL) 304479697Snon return NULL; 304579697Snon 304679697Snon cb = TAILQ_FIRST(&li->li_discq); 304771999Sphk for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain)) 304879697Snon if (cb->ccb_tag == tag) 304967468Snon goto found; 305067468Snon return cb; 305167468Snon 305267468Snon /* 305367468Snon * establish our ccb nexus 305467468Snon */ 305567468Snonfound: 305679697Snon#ifdef SCSI_LOW_DEBUG 305779697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0) 305879697Snon { 305979697Snon printf("%s: nexus(0x%lx) abort check start\n", 306079697Snon slp->sl_xname, (u_long) cb); 306179697Snon cb->ccb_flags |= (CCB_NORETRY | CCB_SILENT); 306279697Snon scsi_low_revoke_ccb(slp, cb, 1); 306379697Snon return NULL; 306479697Snon } 306567468Snon 306679697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id) != 0) 306779697Snon { 306879697Snon if (cb->ccb_omsgoutflag == 0) 306979697Snon scsi_low_ccb_message_assert(cb, SCSI_LOW_MSG_NOOP); 307079697Snon } 307179697Snon#endif /* SCSI_LOW_DEBUG */ 307279697Snon 307379697Snon TAILQ_REMOVE(&li->li_discq, cb, ccb_chain); 307479697Snon cb->ccb_flags &= ~CCB_DISCQ; 307579697Snon slp->sl_Qnexus = cb; 307679697Snon 307767468Snon slp->sl_scp = cb->ccb_sscp; 307867468Snon slp->sl_error |= cb->ccb_error; 307967468Snon 308067468Snon slp->sl_disc --; 308179697Snon ti->ti_disc --; 308267468Snon li->li_disc --; 308367468Snon 308467468Snon /* inform "ccb nexus established" to the host driver */ 308579697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 308679697Snon 308779697Snon /* check msg */ 308879697Snon if (cb->ccb_msgoutflag != 0) 308979697Snon { 309079697Snon scsi_low_ccb_message_exec(slp, cb); 309179697Snon } 309279697Snon 309367468Snon return cb; 309467468Snon} 309567468Snon 309667468Snonstruct targ_info * 309767468Snonscsi_low_reselected(slp, targ) 309867468Snon struct scsi_low_softc *slp; 309967468Snon u_int targ; 310067468Snon{ 310167468Snon struct targ_info *ti; 310279697Snon struct slccb *cb; 310367468Snon u_char *s; 310467468Snon 310567468Snon /* 310667468Snon * Check select vs reselected collision. 310767468Snon */ 310867468Snon 310979697Snon if ((cb = slp->sl_selid) != NULL) 311067468Snon { 311179697Snon scsi_low_arbit_fail(slp, cb); 311267468Snon#ifdef SCSI_LOW_STATICS 311367468Snon scsi_low_statics.nexus_conflict ++; 311467468Snon#endif /* SCSI_LOW_STATICS */ 311567468Snon } 311679697Snon 311779697Snon /* 311879697Snon * Check if no current active nexus. 311979697Snon */ 312079697Snon if (slp->sl_Tnexus != NULL) 312167468Snon { 312267468Snon s = "host busy"; 312367468Snon goto world_restart; 312467468Snon } 312567468Snon 312667468Snon /* 312767468Snon * Check a valid target id asserted ? 312867468Snon */ 312967468Snon if (targ >= slp->sl_ntargs || targ == slp->sl_hostid) 313067468Snon { 313167468Snon s = "scsi id illegal"; 313267468Snon goto world_restart; 313367468Snon } 313467468Snon 313567468Snon /* 313667468Snon * Check the target scsi status. 313767468Snon */ 313867468Snon ti = slp->sl_ti[targ]; 313979697Snon if (ti->ti_phase != PH_DISC && ti->ti_phase != PH_NULL) 314067468Snon { 314167468Snon s = "phase mismatch"; 314267468Snon goto world_restart; 314367468Snon } 314467468Snon 314567468Snon /* 314679697Snon * Setup init msgsys 314767468Snon */ 314867468Snon slp->sl_error = 0; 314967468Snon scsi_low_init_msgsys(slp, ti); 315067468Snon 315167468Snon /* 315267468Snon * Establish our target nexus 315367468Snon */ 315467468Snon SCSI_LOW_SETUP_PHASE(ti, PH_RESEL); 315579697Snon slp->sl_Tnexus = ti; 315667468Snon#ifdef SCSI_LOW_STATICS 315767468Snon scsi_low_statics.nexus_reselected ++; 315867468Snon#endif /* SCSI_LOW_STATICS */ 315967468Snon return ti; 316067468Snon 316167468Snonworld_restart: 316267468Snon printf("%s: reselect(%x:unknown) %s\n", slp->sl_xname, targ, s); 316367468Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, 316467468Snon "reselect: scsi world confused"); 316567468Snon return NULL; 316667468Snon} 316767468Snon 316867468Snon/************************************************************** 316967468Snon * cmd out pointer setup 317067468Snon **************************************************************/ 317167468Snonint 317267468Snonscsi_low_cmd(slp, ti) 317367468Snon struct scsi_low_softc *slp; 317467468Snon struct targ_info *ti; 317567468Snon{ 317679697Snon struct slccb *cb = slp->sl_Qnexus; 317767468Snon 317879697Snon slp->sl_ph_count ++; 317967468Snon if (cb == NULL) 318067468Snon { 318167468Snon /* 318279697Snon * no ccb, abort! 318367468Snon */ 318467468Snon slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd; 318567468Snon slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd); 318667468Snon slp->sl_scp.scp_datalen = 0; 318767468Snon slp->sl_scp.scp_direction = SCSI_LOW_READ; 318879697Snon slp->sl_error |= FATALIO; 318979697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 319079697Snon SCSI_LOW_INFO(slp, ti, "CMDOUT: ccb nexus not found"); 319179697Snon return EINVAL; 319267468Snon } 319379697Snon else 319467468Snon { 319579697Snon#ifdef SCSI_LOW_DEBUG 319679697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_CMDLNK_CHECK, ti->ti_id)) 319779697Snon { 319879697Snon scsi_low_test_cmdlnk(slp, cb); 319979697Snon } 320079697Snon#endif /* SCSI_LOW_DEBUG */ 320167468Snon } 320267468Snon return 0; 320367468Snon} 320467468Snon 320567468Snon/************************************************************** 320667468Snon * data out pointer setup 320767468Snon **************************************************************/ 320867468Snonint 320967468Snonscsi_low_data(slp, ti, bp, direction) 321067468Snon struct scsi_low_softc *slp; 321167468Snon struct targ_info *ti; 321267468Snon struct buf **bp; 321367468Snon int direction; 321467468Snon{ 321579697Snon struct slccb *cb = slp->sl_Qnexus; 321667468Snon 321779697Snon if (cb != NULL && direction == cb->ccb_sscp.scp_direction) 321867468Snon { 321979697Snon *bp = cb->bp; 322079697Snon return 0; 322167468Snon } 322267468Snon 322379697Snon slp->sl_error |= (FATALIO | PDMAERR); 322479697Snon slp->sl_scp.scp_datalen = 0; 322579697Snon slp->sl_scp.scp_direction = direction; 322679697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 322779697Snon if (ti->ti_ophase != ti->ti_phase) 322867468Snon { 322979697Snon char *s; 323079697Snon 323179697Snon if (cb == NULL) 323279697Snon s = "DATA PHASE: ccb nexus not found"; 323379697Snon else 323479697Snon s = "DATA PHASE: xfer direction mismatch"; 323579697Snon SCSI_LOW_INFO(slp, ti, s); 323667468Snon } 323767468Snon 323879697Snon *bp = NULL; 323979697Snon return EINVAL; 324067468Snon} 324167468Snon 324267468Snon/************************************************************** 324367468Snon * MSG_SYS 324467468Snon **************************************************************/ 324567468Snon#define MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;} 324667468Snon#define MSGIN_PERIOD(ti) ((ti)->ti_msgin[3]) 324767468Snon#define MSGIN_OFFSET(ti) ((ti)->ti_msgin[4]) 324879697Snon#define MSGIN_WIDTHP(ti) ((ti)->ti_msgin[3]) 324967468Snon#define MSGIN_DATA_LAST 0x30 325067468Snon 325192770Salfredstatic int scsi_low_errfunc_synch(struct scsi_low_softc *, u_int); 325292770Salfredstatic int scsi_low_errfunc_wide(struct scsi_low_softc *, u_int); 325392770Salfredstatic int scsi_low_errfunc_identify(struct scsi_low_softc *, u_int); 325492770Salfredstatic int scsi_low_errfunc_qtag(struct scsi_low_softc *, u_int); 325567468Snon 325692770Salfredstatic int scsi_low_msgfunc_synch(struct scsi_low_softc *); 325792770Salfredstatic int scsi_low_msgfunc_wide(struct scsi_low_softc *); 325892770Salfredstatic int scsi_low_msgfunc_identify(struct scsi_low_softc *); 325992770Salfredstatic int scsi_low_msgfunc_abort(struct scsi_low_softc *); 326092770Salfredstatic int scsi_low_msgfunc_qabort(struct scsi_low_softc *); 326192770Salfredstatic int scsi_low_msgfunc_qtag(struct scsi_low_softc *); 326292770Salfredstatic int scsi_low_msgfunc_reset(struct scsi_low_softc *); 326367468Snon 326467468Snonstruct scsi_low_msgout_data { 326567468Snon u_int md_flags; 326667468Snon u_int8_t md_msg; 326792770Salfred int (*md_msgfunc)(struct scsi_low_softc *); 326892770Salfred int (*md_errfunc)(struct scsi_low_softc *, u_int); 326979697Snon#define MSG_RELEASE_ATN 0x0001 327079697Snon u_int md_condition; 327167468Snon}; 327267468Snon 327367468Snonstruct scsi_low_msgout_data scsi_low_msgout_data[] = { 327479697Snon/* 0 */ {SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_reset, NULL, MSG_RELEASE_ATN}, 327579697Snon/* 1 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL, MSG_RELEASE_ATN}, 327679697Snon/* 2 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL, MSG_RELEASE_ATN}, 327779697Snon/* 3 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL, MSG_RELEASE_ATN}, 327879697Snon/* 4 */ {SCSI_LOW_MSG_IDENTIFY, MSG_IDENTIFY, scsi_low_msgfunc_identify, scsi_low_errfunc_identify, 0}, 327979697Snon/* 5 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN}, 328079697Snon/* 6 */ {SCSI_LOW_MSG_TERMIO, MSG_TERM_IO, NULL, NULL, MSG_RELEASE_ATN}, 328179697Snon/* 7 */ {SCSI_LOW_MSG_SIMPLE_QTAG, MSG_SIMPLE_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 328279697Snon/* 8 */ {SCSI_LOW_MSG_ORDERED_QTAG, MSG_ORDERED_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 328379697Snon/* 9 */{SCSI_LOW_MSG_HEAD_QTAG, MSG_HEAD_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0}, 328479697Snon/* 10 */ {SCSI_LOW_MSG_ABORT_QTAG, MSG_ABORT_QTAG, scsi_low_msgfunc_qabort, NULL, MSG_RELEASE_ATN}, 328579697Snon/* 11 */ {SCSI_LOW_MSG_CLEAR_QTAG, MSG_CLEAR_QTAG, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN}, 328679697Snon/* 12 */{SCSI_LOW_MSG_WIDE, MSG_EXTEND, scsi_low_msgfunc_wide, scsi_low_errfunc_wide, MSG_RELEASE_ATN}, 328779697Snon/* 13 */{SCSI_LOW_MSG_SYNCH, MSG_EXTEND, scsi_low_msgfunc_synch, scsi_low_errfunc_synch, MSG_RELEASE_ATN}, 328879697Snon/* 14 */{SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL, MSG_RELEASE_ATN}, 328979697Snon/* 15 */{SCSI_LOW_MSG_ALL, 0}, 329067468Snon}; 329167468Snon 329292770Salfredstatic int scsi_low_msginfunc_ext(struct scsi_low_softc *); 329392770Salfredstatic int scsi_low_synch(struct scsi_low_softc *); 329492770Salfredstatic int scsi_low_wide(struct scsi_low_softc *); 329592770Salfredstatic int scsi_low_msginfunc_msg_reject(struct scsi_low_softc *); 329692770Salfredstatic int scsi_low_msginfunc_rejop(struct scsi_low_softc *); 329792770Salfredstatic int scsi_low_msginfunc_rp(struct scsi_low_softc *); 329892770Salfredstatic int scsi_low_msginfunc_sdp(struct scsi_low_softc *); 329992770Salfredstatic int scsi_low_msginfunc_disc(struct scsi_low_softc *); 330092770Salfredstatic int scsi_low_msginfunc_cc(struct scsi_low_softc *); 330192770Salfredstatic int scsi_low_msginfunc_lcc(struct scsi_low_softc *); 330292770Salfredstatic int scsi_low_msginfunc_parity(struct scsi_low_softc *); 330392770Salfredstatic int scsi_low_msginfunc_noop(struct scsi_low_softc *); 330492770Salfredstatic int scsi_low_msginfunc_simple_qtag(struct scsi_low_softc *); 330592770Salfredstatic int scsi_low_msginfunc_i_wide_residue(struct scsi_low_softc *); 330667468Snon 330767468Snonstruct scsi_low_msgin_data { 330867468Snon u_int md_len; 330992770Salfred int (*md_msgfunc)(struct scsi_low_softc *); 331067468Snon}; 331167468Snon 331267468Snonstruct scsi_low_msgin_data scsi_low_msgin_data[] = { 331367468Snon/* 0 */ {1, scsi_low_msginfunc_cc}, 331467468Snon/* 1 */ {2, scsi_low_msginfunc_ext}, 331567468Snon/* 2 */ {1, scsi_low_msginfunc_sdp}, 331679697Snon/* 3 */ {1, scsi_low_msginfunc_rp}, 331767468Snon/* 4 */ {1, scsi_low_msginfunc_disc}, 331867468Snon/* 5 */ {1, scsi_low_msginfunc_rejop}, 331967468Snon/* 6 */ {1, scsi_low_msginfunc_rejop}, 332067468Snon/* 7 */ {1, scsi_low_msginfunc_msg_reject}, 332167468Snon/* 8 */ {1, scsi_low_msginfunc_noop}, 332267468Snon/* 9 */ {1, scsi_low_msginfunc_parity}, 332379697Snon/* a */ {1, scsi_low_msginfunc_lcc}, 332479697Snon/* b */ {1, scsi_low_msginfunc_lcc}, 332567468Snon/* c */ {1, scsi_low_msginfunc_rejop}, 332667468Snon/* d */ {2, scsi_low_msginfunc_rejop}, 332767468Snon/* e */ {1, scsi_low_msginfunc_rejop}, 332867468Snon/* f */ {1, scsi_low_msginfunc_rejop}, 332967468Snon/* 0x10 */ {1, scsi_low_msginfunc_rejop}, 333067468Snon/* 0x11 */ {1, scsi_low_msginfunc_rejop}, 333167468Snon/* 0x12 */ {1, scsi_low_msginfunc_rejop}, 333267468Snon/* 0x13 */ {1, scsi_low_msginfunc_rejop}, 333367468Snon/* 0x14 */ {1, scsi_low_msginfunc_rejop}, 333467468Snon/* 0x15 */ {1, scsi_low_msginfunc_rejop}, 333567468Snon/* 0x16 */ {1, scsi_low_msginfunc_rejop}, 333667468Snon/* 0x17 */ {1, scsi_low_msginfunc_rejop}, 333767468Snon/* 0x18 */ {1, scsi_low_msginfunc_rejop}, 333867468Snon/* 0x19 */ {1, scsi_low_msginfunc_rejop}, 333967468Snon/* 0x1a */ {1, scsi_low_msginfunc_rejop}, 334067468Snon/* 0x1b */ {1, scsi_low_msginfunc_rejop}, 334167468Snon/* 0x1c */ {1, scsi_low_msginfunc_rejop}, 334267468Snon/* 0x1d */ {1, scsi_low_msginfunc_rejop}, 334367468Snon/* 0x1e */ {1, scsi_low_msginfunc_rejop}, 334467468Snon/* 0x1f */ {1, scsi_low_msginfunc_rejop}, 334579697Snon/* 0x20 */ {2, scsi_low_msginfunc_simple_qtag}, 334667468Snon/* 0x21 */ {2, scsi_low_msginfunc_rejop}, 334767468Snon/* 0x22 */ {2, scsi_low_msginfunc_rejop}, 334879697Snon/* 0x23 */ {2, scsi_low_msginfunc_i_wide_residue}, 334967468Snon/* 0x24 */ {2, scsi_low_msginfunc_rejop}, 335067468Snon/* 0x25 */ {2, scsi_low_msginfunc_rejop}, 335167468Snon/* 0x26 */ {2, scsi_low_msginfunc_rejop}, 335267468Snon/* 0x27 */ {2, scsi_low_msginfunc_rejop}, 335367468Snon/* 0x28 */ {2, scsi_low_msginfunc_rejop}, 335467468Snon/* 0x29 */ {2, scsi_low_msginfunc_rejop}, 335567468Snon/* 0x2a */ {2, scsi_low_msginfunc_rejop}, 335667468Snon/* 0x2b */ {2, scsi_low_msginfunc_rejop}, 335767468Snon/* 0x2c */ {2, scsi_low_msginfunc_rejop}, 335867468Snon/* 0x2d */ {2, scsi_low_msginfunc_rejop}, 335967468Snon/* 0x2e */ {2, scsi_low_msginfunc_rejop}, 336067468Snon/* 0x2f */ {2, scsi_low_msginfunc_rejop}, 336167468Snon/* 0x30 */ {1, scsi_low_msginfunc_rejop} /* default rej op */ 336267468Snon}; 336367468Snon 336467468Snon/************************************************************** 336567468Snon * msgout 336667468Snon **************************************************************/ 336767468Snonstatic int 336879697Snonscsi_low_msgfunc_synch(slp) 336979697Snon struct scsi_low_softc *slp; 337067468Snon{ 337179697Snon struct targ_info *ti = slp->sl_Tnexus; 337267468Snon int ptr = ti->ti_msgoutlen; 337367468Snon 337467468Snon ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN; 337567468Snon ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE; 337673025Snon ti->ti_msgoutstr[ptr + 3] = ti->ti_maxsynch.period; 337773025Snon ti->ti_msgoutstr[ptr + 4] = ti->ti_maxsynch.offset; 337867468Snon return MSG_EXTEND_SYNCHLEN + 2; 337967468Snon} 338067468Snon 338167468Snonstatic int 338279697Snonscsi_low_msgfunc_wide(slp) 338379697Snon struct scsi_low_softc *slp; 338467468Snon{ 338579697Snon struct targ_info *ti = slp->sl_Tnexus; 338667468Snon int ptr = ti->ti_msgoutlen; 338767468Snon 338867468Snon ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN; 338967468Snon ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE; 339073025Snon ti->ti_msgoutstr[ptr + 3] = ti->ti_width; 339167468Snon return MSG_EXTEND_WIDELEN + 2; 339267468Snon} 339367468Snon 339467468Snonstatic int 339579697Snonscsi_low_msgfunc_identify(slp) 339679697Snon struct scsi_low_softc *slp; 339767468Snon{ 339879697Snon struct targ_info *ti = slp->sl_Tnexus; 339979697Snon struct lun_info *li = slp->sl_Lnexus; 340079697Snon struct slccb *cb = slp->sl_Qnexus; 340179697Snon int ptr = ti->ti_msgoutlen; 340279697Snon u_int8_t msg; 340367468Snon 340479697Snon msg = MSG_IDENTIFY; 340579697Snon if (cb == NULL) 340667468Snon { 340779697Snon slp->sl_error |= FATALIO; 340879697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 340979697Snon SCSI_LOW_INFO(slp, ti, "MSGOUT: nexus unknown"); 341067468Snon } 341167468Snon else 341267468Snon { 341379697Snon if (scsi_low_is_disconnect_ok(cb) != 0) 341479697Snon msg |= (MSG_IDENTIFY_DISCPRIV | li->li_lun); 341579697Snon else 341679697Snon msg |= li->li_lun; 341779697Snon 341879697Snon if (ti->ti_phase == PH_MSGOUT) 341979697Snon { 342079697Snon (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp); 342179697Snon if (cb->ccb_tag == SCSI_LOW_UNKTAG) 342279697Snon { 342379697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 342479697Snon } 342579697Snon } 342667468Snon } 342779697Snon ti->ti_msgoutstr[ptr + 0] = msg; 342867468Snon return 1; 342967468Snon} 343067468Snon 343167468Snonstatic int 343279697Snonscsi_low_msgfunc_abort(slp) 343379697Snon struct scsi_low_softc *slp; 343467468Snon{ 343567468Snon 343679697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_ABORT); 343779697Snon return 1; 343879697Snon} 343979697Snon 344079697Snonstatic int 344179697Snonscsi_low_msgfunc_qabort(slp) 344279697Snon struct scsi_low_softc *slp; 344379697Snon{ 344479697Snon 344579697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_TERM); 344679697Snon return 1; 344779697Snon} 344879697Snon 344979697Snonstatic int 345079697Snonscsi_low_msgfunc_reset(slp) 345179697Snon struct scsi_low_softc *slp; 345279697Snon{ 345379697Snon 345479697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_RESET); 345579697Snon return 1; 345679697Snon} 345779697Snon 345879697Snonstatic int 345979697Snonscsi_low_msgfunc_qtag(slp) 346079697Snon struct scsi_low_softc *slp; 346179697Snon{ 346279697Snon struct targ_info *ti = slp->sl_Tnexus; 346379697Snon struct slccb *cb = slp->sl_Qnexus; 346479697Snon int ptr = ti->ti_msgoutlen; 346579697Snon 346679697Snon if (cb == NULL || cb->ccb_tag == SCSI_LOW_UNKTAG) 346767468Snon { 346867468Snon ti->ti_msgoutstr[ptr + 0] = MSG_NOOP; 346967468Snon return 1; 347067468Snon } 347167468Snon else 347267468Snon { 347379697Snon ti->ti_msgoutstr[ptr + 1] = (u_int8_t) cb->ccb_tag; 347479697Snon if (ti->ti_phase == PH_MSGOUT) 347579697Snon { 347679697Snon (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp); 347779697Snon } 347867468Snon } 347979697Snon return 2; 348067468Snon} 348167468Snon 348267468Snon/* 348367468Snon * The following functions are called when targets give unexpected 348467468Snon * responces in msgin (after msgout). 348567468Snon */ 348667468Snonstatic int 348779697Snonscsi_low_errfunc_identify(slp, msgflags) 348879697Snon struct scsi_low_softc *slp; 348967468Snon u_int msgflags; 349067468Snon{ 349167468Snon 349279697Snon if (slp->sl_Lnexus != NULL) 349379697Snon { 349479697Snon slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_DISC; 349579697Snon scsi_low_calcf_lun(slp->sl_Lnexus); 349679697Snon } 349767468Snon return 0; 349867468Snon} 349967468Snon 350067468Snonstatic int 350179697Snonscsi_low_errfunc_synch(slp, msgflags) 350279697Snon struct scsi_low_softc *slp; 350367468Snon u_int msgflags; 350467468Snon{ 350579697Snon struct targ_info *ti = slp->sl_Tnexus; 350667468Snon 350767468Snon MSGIN_PERIOD(ti) = 0; 350867468Snon MSGIN_OFFSET(ti) = 0; 350979697Snon scsi_low_synch(slp); 351067468Snon return 0; 351167468Snon} 351267468Snon 351367468Snonstatic int 351479697Snonscsi_low_errfunc_wide(slp, msgflags) 351579697Snon struct scsi_low_softc *slp; 351667468Snon u_int msgflags; 351767468Snon{ 351879697Snon struct targ_info *ti = slp->sl_Tnexus; 351979697Snon 352079697Snon MSGIN_WIDTHP(ti) = 0; 352179697Snon scsi_low_wide(slp); 352267468Snon return 0; 352367468Snon} 352467468Snon 352579697Snonstatic int 352679697Snonscsi_low_errfunc_qtag(slp, msgflags) 352779697Snon struct scsi_low_softc *slp; 352879697Snon u_int msgflags; 352979697Snon{ 353079697Snon 353179697Snon if ((msgflags & SCSI_LOW_MSG_REJECT) != 0) 353279697Snon { 353379697Snon if (slp->sl_Qnexus != NULL) 353479697Snon { 353579697Snon scsi_low_deactivate_qtag(slp->sl_Qnexus); 353679697Snon } 353779697Snon if (slp->sl_Lnexus != NULL) 353879697Snon { 353979697Snon slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_QTAG; 354079697Snon scsi_low_calcf_lun(slp->sl_Lnexus); 354179697Snon } 354279697Snon printf("%s: scsi_low: qtag msg rejected\n", slp->sl_xname); 354379697Snon } 354479697Snon return 0; 354579697Snon} 354679697Snon 354779697Snon 354867468Snonint 354979697Snonscsi_low_msgout(slp, ti, fl) 355067468Snon struct scsi_low_softc *slp; 355167468Snon struct targ_info *ti; 355279697Snon u_int fl; 355367468Snon{ 355467468Snon struct scsi_low_msgout_data *mdp; 355567468Snon int len = 0; 355667468Snon 355779697Snon#ifdef SCSI_LOW_DIAGNOSTIC 355879697Snon if (ti != slp->sl_Tnexus) 355979697Snon { 356079697Snon scsi_low_print(slp, NULL); 356179697Snon panic("scsi_low_msgout: Target nexus inconsistent"); 356279697Snon } 356379697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 356479697Snon 356579697Snon slp->sl_ph_count ++; 356679697Snon if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES) 356779697Snon { 356879697Snon printf("%s: too many phase changes\n", slp->sl_xname); 356979697Snon slp->sl_error |= FATALIO; 357079697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 357179697Snon } 357279697Snon 357367468Snon /* STEP I. 357467468Snon * Scsi phase changes. 357567468Snon * Previously msgs asserted are accepted by our target or 357667468Snon * processed by scsi_low_msgin. 357767468Snon * Thus clear all saved informations. 357867468Snon */ 357979697Snon if ((fl & SCSI_LOW_MSGOUT_INIT) != 0) 358067468Snon { 358167468Snon ti->ti_omsgflags = 0; 358267468Snon ti->ti_emsgflags = 0; 358367468Snon } 358479697Snon else if (slp->sl_atten == 0) 358579697Snon { 358667468Snon /* STEP II. 358767468Snon * We did not assert attention, however still our target required 358867468Snon * msgs. Resend previous msgs. 358967468Snon */ 359067468Snon ti->ti_msgflags |= ti->ti_omsgflags; 359179697Snon ti->ti_omsgflags = 0; 359267468Snon#ifdef SCSI_LOW_DIAGNOSTIC 359367468Snon printf("%s: scsi_low_msgout: retry msgout\n", slp->sl_xname); 359467468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 359567468Snon } 359667468Snon 359767468Snon /* STEP III. 359879697Snon * We have no msgs. send MSG_NOOP (OK?) 359967468Snon */ 360079697Snon if (scsi_low_is_msgout_continue(ti, 0) == 0) 360167468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0); 360267468Snon 360367468Snon /* STEP IV. 360467468Snon * Process all msgs 360567468Snon */ 360667468Snon ti->ti_msgoutlen = 0; 360779697Snon slp->sl_clear_atten = 0; 360867468Snon mdp = &scsi_low_msgout_data[0]; 360967468Snon for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) 361067468Snon { 361167468Snon if ((ti->ti_msgflags & mdp->md_flags) != 0) 361267468Snon { 361367468Snon ti->ti_omsgflags |= mdp->md_flags; 361467468Snon ti->ti_msgflags &= ~mdp->md_flags; 361567468Snon ti->ti_emsgflags = mdp->md_flags; 361667468Snon 361767468Snon ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg; 361867468Snon if (mdp->md_msgfunc != NULL) 361979697Snon len = (*mdp->md_msgfunc) (slp); 362067468Snon else 362167468Snon len = 1; 362267468Snon 362379697Snon#ifdef SCSI_LOW_DIAGNOSTIC 362479697Snon scsi_low_msg_log_write(&ti->ti_log_msgout, 362579697Snon &ti->ti_msgoutstr[ti->ti_msgoutlen], len); 362679697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 362779697Snon 362867468Snon ti->ti_msgoutlen += len; 362979697Snon if ((mdp->md_condition & MSG_RELEASE_ATN) != 0) 363079697Snon { 363179697Snon slp->sl_clear_atten = 1; 363279697Snon break; 363379697Snon } 363479697Snon 363579697Snon if ((fl & SCSI_LOW_MSGOUT_UNIFY) == 0 || 363667468Snon ti->ti_msgflags == 0) 363767468Snon break; 363879697Snon 363967468Snon if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5) 364067468Snon break; 364167468Snon } 364267468Snon } 364367468Snon 364479697Snon if (scsi_low_is_msgout_continue(ti, 0) == 0) 364579697Snon slp->sl_clear_atten = 1; 364667468Snon 364767468Snon return ti->ti_msgoutlen; 364867468Snon} 364967468Snon 365067468Snon/************************************************************** 365167468Snon * msgin 365267468Snon **************************************************************/ 365367468Snonstatic int 365479697Snonscsi_low_msginfunc_noop(slp) 365579697Snon struct scsi_low_softc *slp; 365667468Snon{ 365767468Snon 365867468Snon return 0; 365967468Snon} 366067468Snon 366167468Snonstatic int 366279697Snonscsi_low_msginfunc_rejop(slp) 366379697Snon struct scsi_low_softc *slp; 366467468Snon{ 366579697Snon struct targ_info *ti = slp->sl_Tnexus; 366667468Snon u_int8_t msg = ti->ti_msgin[0]; 366767468Snon 366879697Snon printf("%s: MSGIN: msg 0x%x rejected\n", slp->sl_xname, (u_int) msg); 366967468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 367067468Snon return 0; 367167468Snon} 367267468Snon 367367468Snonstatic int 367479697Snonscsi_low_msginfunc_cc(slp) 367579697Snon struct scsi_low_softc *slp; 367667468Snon{ 367779697Snon struct lun_info *li; 367867468Snon 367967468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); 368079697Snon 368179697Snon /* validate status */ 368279697Snon if (slp->sl_Qnexus == NULL) 368379697Snon return ENOENT; 368479697Snon 368579697Snon slp->sl_Qnexus->ccb_sscp.scp_status = slp->sl_scp.scp_status; 368679697Snon li = slp->sl_Lnexus; 368779697Snon switch (slp->sl_scp.scp_status) 368879697Snon { 368979697Snon case ST_GOOD: 369079697Snon li->li_maxnqio = li->li_maxnexus; 369179697Snon break; 369279697Snon 369379697Snon case ST_CHKCOND: 369479697Snon li->li_maxnqio = 0; 369579697Snon if (li->li_qflags & SCSI_LOW_QFLAG_CA_QCLEAR) 369679697Snon scsi_low_reset_nexus_lun(slp, li, 0); 369779697Snon break; 369879697Snon 369979697Snon case ST_BUSY: 370079697Snon li->li_maxnqio = 0; 370179697Snon break; 370279697Snon 370379697Snon case ST_QUEFULL: 370479697Snon if (li->li_maxnexus >= li->li_nqio) 370579697Snon li->li_maxnexus = li->li_nqio - 1; 370679697Snon li->li_maxnqio = li->li_maxnexus; 370779697Snon break; 370879697Snon 370979697Snon case ST_INTERGOOD: 371079697Snon case ST_INTERMET: 371179697Snon slp->sl_error |= MSGERR; 371279697Snon break; 371379697Snon 371479697Snon default: 371579697Snon break; 371679697Snon } 371767468Snon return 0; 371867468Snon} 371967468Snon 372067468Snonstatic int 372179697Snonscsi_low_msginfunc_lcc(slp) 372279697Snon struct scsi_low_softc *slp; 372379697Snon{ 372467468Snon struct targ_info *ti; 372579697Snon struct lun_info *li; 372679697Snon struct slccb *ncb, *cb; 372779697Snon 372879697Snon ti = slp->sl_Tnexus; 372979697Snon li = slp->sl_Lnexus; 373079697Snon if ((cb = slp->sl_Qnexus) == NULL) 373179697Snon goto bad; 373279697Snon 373379697Snon cb->ccb_sscp.scp_status = slp->sl_scp.scp_status; 373479697Snon switch (slp->sl_scp.scp_status) 373579697Snon { 373679697Snon case ST_INTERGOOD: 373779697Snon case ST_INTERMET: 373879697Snon li->li_maxnqio = li->li_maxnexus; 373979697Snon break; 374079697Snon 374179697Snon default: 374279697Snon slp->sl_error |= MSGERR; 374379697Snon break; 374479697Snon } 374579697Snon 374679697Snon if ((li->li_flags & SCSI_LOW_LINK) == 0) 374779697Snon goto bad; 374879697Snon 374979697Snon cb->ccb_error |= slp->sl_error; 375079697Snon if (cb->ccb_error != 0) 375179697Snon goto bad; 375279697Snon 375379697Snon for (ncb = TAILQ_FIRST(&slp->sl_start); ncb != NULL; 375479697Snon ncb = TAILQ_NEXT(ncb, ccb_chain)) 375579697Snon { 375679697Snon if (ncb->li == li) 375779697Snon goto cmd_link_start; 375879697Snon } 375979697Snon 376079697Snon 376179697Snonbad: 376279697Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_LCTERM); 376379697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 376479697Snon return EIO; 376579697Snon 376679697Snoncmd_link_start: 376779697Snon ncb->ccb_flags &= ~CCB_STARTQ; 376879697Snon TAILQ_REMOVE(&slp->sl_start, ncb, ccb_chain); 376979697Snon 377079697Snon scsi_low_dealloc_qtag(ncb); 377179697Snon ncb->ccb_tag = cb->ccb_tag; 377279697Snon ncb->ccb_otag = cb->ccb_otag; 377379697Snon cb->ccb_tag = SCSI_LOW_UNKTAG; 377479697Snon cb->ccb_otag = SCSI_LOW_UNKTAG; 377579697Snon if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY) 377679697Snon panic("%s: linked ccb retried\n", slp->sl_xname); 377779697Snon 377879697Snon slp->sl_Qnexus = ncb; 377979697Snon slp->sl_ph_count = 0; 378079697Snon 378179697Snon ncb->ccb_error = 0; 378279697Snon ncb->ccb_datalen = -1; 378379697Snon ncb->ccb_scp.scp_status = ST_UNKNOWN; 378479697Snon ncb->ccb_flags &= ~CCB_INTERNAL; 378579697Snon 378679697Snon scsi_low_init_msgsys(slp, ti); 378779697Snon 378879697Snon (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, ncb); 378979697Snon 379079697Snon if (ncb->ccb_tcmax < SCSI_LOW_MIN_TOUT) 379179697Snon ncb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 379279697Snon ncb->ccb_tc = ncb->ccb_tcmax; 379379697Snon 379479697Snon /* setup saved scsi data pointer */ 379579697Snon ncb->ccb_sscp = ncb->ccb_scp; 379679697Snon slp->sl_scp = ncb->ccb_sscp; 379779697Snon slp->sl_error = ncb->ccb_error; 379879697Snon 379979697Snon#ifdef SCSI_LOW_DIAGNOSTIC 380079697Snon scsi_low_msg_log_init(&ti->ti_log_msgin); 380179697Snon scsi_low_msg_log_init(&ti->ti_log_msgout); 380279697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 380379697Snon return EJUSTRETURN; 380479697Snon} 380579697Snon 380679697Snonstatic int 380779697Snonscsi_low_msginfunc_disc(slp) 380879697Snon struct scsi_low_softc *slp; 380967468Snon{ 381067468Snon 381167468Snon SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC); 381267468Snon return 0; 381367468Snon} 381467468Snon 381567468Snonstatic int 381679697Snonscsi_low_msginfunc_sdp(slp) 381779697Snon struct scsi_low_softc *slp; 381867468Snon{ 381979697Snon struct slccb *cb = slp->sl_Qnexus; 382067468Snon 382179697Snon if (cb != NULL) 382279697Snon { 382379697Snon cb->ccb_sscp.scp_datalen = slp->sl_scp.scp_datalen; 382479697Snon cb->ccb_sscp.scp_data = slp->sl_scp.scp_data; 382579697Snon } 382667468Snon else 382779697Snon scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0); 382867468Snon return 0; 382967468Snon} 383067468Snon 383167468Snonstatic int 383279697Snonscsi_low_msginfunc_rp(slp) 383379697Snon struct scsi_low_softc *slp; 383467468Snon{ 383567468Snon 383679697Snon if (slp->sl_Qnexus != NULL) 383779697Snon slp->sl_scp = slp->sl_Qnexus->ccb_sscp; 383867468Snon else 383979697Snon scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0); 384067468Snon return 0; 384167468Snon} 384267468Snon 384367468Snonstatic int 384479697Snonscsi_low_synch(slp) 384579697Snon struct scsi_low_softc *slp; 384667468Snon{ 384779697Snon struct targ_info *ti = slp->sl_Tnexus; 384879697Snon u_int period = 0, offset = 0, speed; 384967468Snon u_char *s; 385067468Snon int error; 385167468Snon 385279697Snon if ((MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period && 385379697Snon MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset) || 385479697Snon MSGIN_OFFSET(ti) == 0) 385567468Snon { 385667468Snon if ((offset = MSGIN_OFFSET(ti)) != 0) 385767468Snon period = MSGIN_PERIOD(ti); 385867468Snon s = offset ? "synchronous" : "async"; 385967468Snon } 386067468Snon else 386167468Snon { 386267468Snon /* XXX: 386367468Snon * Target seems to be brain damaged. 386467468Snon * Force async transfer. 386567468Snon */ 386673025Snon ti->ti_maxsynch.period = 0; 386773025Snon ti->ti_maxsynch.offset = 0; 386867468Snon printf("%s: target brain damaged. async transfer\n", 386967468Snon slp->sl_xname); 387067468Snon return EINVAL; 387167468Snon } 387267468Snon 387373025Snon ti->ti_maxsynch.period = period; 387473025Snon ti->ti_maxsynch.offset = offset; 387567468Snon 387667468Snon error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH); 387767468Snon if (error != 0) 387867468Snon { 387967468Snon /* XXX: 388067468Snon * Current period and offset are not acceptable 388167468Snon * for our adapter. 388267468Snon * The adapter changes max synch and max offset. 388367468Snon */ 388467468Snon printf("%s: synch neg failed. retry synch msg neg ...\n", 388567468Snon slp->sl_xname); 388667468Snon return error; 388767468Snon } 388867468Snon 388979697Snon ti->ti_osynch = ti->ti_maxsynch; 389079697Snon if (offset > 0) 389179697Snon { 389279697Snon ti->ti_setup_msg_done |= SCSI_LOW_MSG_SYNCH; 389379697Snon } 389479697Snon 389567468Snon /* inform data */ 389679697Snon if ((slp->sl_show_result & SHOW_SYNCH_NEG) != 0) 389767468Snon { 389879697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 389979697Snon struct slccb *cb = slp->sl_Qnexus; 390079697Snon 390179697Snon if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0) 390279697Snon return 0; 390379697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 390479697Snon 390579697Snon printf("%s(%d:*): <%s> offset %d period %dns ", 390679697Snon slp->sl_xname, ti->ti_id, s, offset, period * 4); 390779697Snon 390879697Snon if (period != 0) 390979697Snon { 391079697Snon speed = 1000 * 10 / (period * 4); 391179697Snon printf("%d.%d M/s", speed / 10, speed % 10); 391279697Snon } 391379697Snon printf("\n"); 391467468Snon } 391579697Snon return 0; 391679697Snon} 391767468Snon 391879697Snonstatic int 391979697Snonscsi_low_wide(slp) 392079697Snon struct scsi_low_softc *slp; 392179697Snon{ 392279697Snon struct targ_info *ti = slp->sl_Tnexus; 392379697Snon int error; 392479697Snon 392579697Snon ti->ti_width = MSGIN_WIDTHP(ti); 392679697Snon error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_WIDE); 392779697Snon if (error != 0) 392879697Snon { 392979697Snon /* XXX: 393079697Snon * Current width is not acceptable for our adapter. 393179697Snon * The adapter changes max width. 393279697Snon */ 393379697Snon printf("%s: wide neg failed. retry wide msg neg ...\n", 393479697Snon slp->sl_xname); 393579697Snon return error; 393679697Snon } 393779697Snon 393879697Snon ti->ti_owidth = ti->ti_width; 393979697Snon if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 394079697Snon { 394179697Snon ti->ti_setup_msg_done |= 394279697Snon (SCSI_LOW_MSG_SYNCH | SCSI_LOW_MSG_WIDE); 394379697Snon } 394479697Snon 394579697Snon /* inform data */ 394679697Snon if ((slp->sl_show_result & SHOW_WIDE_NEG) != 0) 394779697Snon { 394879697Snon#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE 394979697Snon struct slccb *cb = slp->sl_Qnexus; 395079697Snon 395179697Snon if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0) 395279697Snon return 0; 395379697Snon#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */ 395479697Snon 395579697Snon printf("%s(%d:*): transfer width %d bits\n", 395679697Snon slp->sl_xname, ti->ti_id, 1 << (3 + ti->ti_width)); 395779697Snon } 395867468Snon return 0; 395967468Snon} 396067468Snon 396167468Snonstatic int 396279697Snonscsi_low_msginfunc_simple_qtag(slp) 396379697Snon struct scsi_low_softc *slp; 396467468Snon{ 396579697Snon struct targ_info *ti = slp->sl_Tnexus; 396679697Snon scsi_low_tag_t etag = (scsi_low_tag_t) ti->ti_msgin[1]; 396779697Snon 396879697Snon if (slp->sl_Qnexus != NULL) 396979697Snon { 397079697Snon if (slp->sl_Qnexus->ccb_tag != etag) 397179697Snon { 397279697Snon slp->sl_error |= FATALIO; 397379697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 397479697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: qtag mismatch"); 397579697Snon } 397679697Snon } 397779697Snon else if (scsi_low_establish_ccb(ti, slp->sl_Lnexus, etag) == NULL) 397879697Snon { 397979697Snon#ifdef SCSI_LOW_DEBUG 398079697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id)) 398179697Snon return 0; 398279697Snon#endif /* SCSI_LOW_DEBUG */ 398379697Snon 398479697Snon slp->sl_error |= FATALIO; 398579697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT_QTAG, 0); 398679697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: taged ccb not found"); 398779697Snon } 398879697Snon return 0; 398979697Snon} 399079697Snon 399179697Snonstatic int 399279697Snonscsi_low_msginfunc_i_wide_residue(slp) 399379697Snon struct scsi_low_softc *slp; 399479697Snon{ 399579697Snon struct targ_info *ti = slp->sl_Tnexus; 399679697Snon struct slccb *cb = slp->sl_Qnexus; 399779697Snon int res = (int) ti->ti_msgin[1]; 399879697Snon 399979697Snon if (cb == NULL || res <= 0 || 400079697Snon (ti->ti_width == SCSI_LOW_BUS_WIDTH_16 && res > 1) || 400179697Snon (ti->ti_width == SCSI_LOW_BUS_WIDTH_32 && res > 3)) 400279697Snon return EINVAL; 400379697Snon 400479697Snon if (slp->sl_scp.scp_datalen + res > cb->ccb_scp.scp_datalen) 400579697Snon return EINVAL; 400679697Snon 400779697Snon slp->sl_scp.scp_datalen += res; 400879697Snon slp->sl_scp.scp_data -= res; 400979697Snon scsi_low_data_finish(slp); 401079697Snon return 0; 401179697Snon} 401279697Snon 401379697Snonstatic int 401479697Snonscsi_low_msginfunc_ext(slp) 401579697Snon struct scsi_low_softc *slp; 401679697Snon{ 401779697Snon struct slccb *cb = slp->sl_Qnexus; 401879697Snon struct lun_info *li = slp->sl_Lnexus; 401979697Snon struct targ_info *ti = slp->sl_Tnexus; 402067468Snon int count, retry; 402167468Snon u_int32_t *ptr; 402267468Snon 402367468Snon if (ti->ti_msginptr == 2) 402467468Snon { 402567468Snon ti->ti_msginlen = ti->ti_msgin[1] + 2; 402667468Snon return 0; 402767468Snon } 402867468Snon 402967468Snon switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2])) 403067468Snon { 403167468Snon case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE): 403267468Snon if (cb == NULL) 403367468Snon break; 403467468Snon 403567468Snon ptr = (u_int32_t *)(&ti->ti_msgin[3]); 403667468Snon count = (int) htonl((long) (*ptr)); 403767468Snon if(slp->sl_scp.scp_datalen - count < 0 || 403867468Snon slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen) 403967468Snon break; 404067468Snon 404167468Snon slp->sl_scp.scp_datalen -= count; 404267468Snon slp->sl_scp.scp_data += count; 404367468Snon return 0; 404467468Snon 404567468Snon case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE): 404667468Snon if (li == NULL) 404767468Snon break; 404867468Snon 404979697Snon retry = scsi_low_synch(slp); 405067468Snon if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0) 405167468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0); 405279697Snon 405379697Snon#ifdef SCSI_LOW_DEBUG 405479697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id)) 405579697Snon { 405679697Snon scsi_low_test_atten(slp, ti, SCSI_LOW_MSG_SYNCH); 405779697Snon } 405879697Snon#endif /* SCSI_LOW_DEBUG */ 405967468Snon return 0; 406067468Snon 406167468Snon case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE): 406267468Snon if (li == NULL) 406367468Snon break; 406467468Snon 406579697Snon retry = scsi_low_wide(slp); 406679697Snon if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_WIDE) == 0) 406779697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0); 406879697Snon 406967468Snon return 0; 407067468Snon 407167468Snon default: 407267468Snon break; 407367468Snon } 407467468Snon 407567468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 407667468Snon return EINVAL; 407767468Snon} 407867468Snon 407967468Snonstatic int 408079697Snonscsi_low_msginfunc_parity(slp) 408179697Snon struct scsi_low_softc *slp; 408267468Snon{ 408379697Snon struct targ_info *ti = slp->sl_Tnexus; 408467468Snon 408579697Snon /* only I -> T, invalid! */ 408679697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 408767468Snon return 0; 408867468Snon} 408967468Snon 409067468Snonstatic int 409179697Snonscsi_low_msginfunc_msg_reject(slp) 409279697Snon struct scsi_low_softc *slp; 409367468Snon{ 409479697Snon struct targ_info *ti = slp->sl_Tnexus; 409567468Snon struct scsi_low_msgout_data *mdp; 409667468Snon u_int msgflags; 409767468Snon 409879697Snon if (ti->ti_emsgflags != 0) 409967468Snon { 410079697Snon printf("%s: msg flags [0x%x] rejected\n", 410179697Snon slp->sl_xname, ti->ti_emsgflags); 410267468Snon msgflags = SCSI_LOW_MSG_REJECT; 410367468Snon mdp = &scsi_low_msgout_data[0]; 410467468Snon for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) 410567468Snon { 410667468Snon if ((ti->ti_emsgflags & mdp->md_flags) != 0) 410767468Snon { 410867468Snon ti->ti_emsgflags &= ~mdp->md_flags; 410967468Snon if (mdp->md_errfunc != NULL) 411079697Snon (*mdp->md_errfunc) (slp, msgflags); 411167468Snon break; 411267468Snon } 411367468Snon } 411479697Snon return 0; 411567468Snon } 411679697Snon else 411779697Snon { 411879697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: rejected msg not found"); 411979697Snon slp->sl_error |= MSGERR; 412079697Snon } 412179697Snon return EINVAL; 412267468Snon} 412367468Snon 412479697Snonint 412567468Snonscsi_low_msgin(slp, ti, c) 412667468Snon struct scsi_low_softc *slp; 412767468Snon struct targ_info *ti; 412879697Snon u_int c; 412967468Snon{ 413067468Snon struct scsi_low_msgin_data *sdp; 413167468Snon struct lun_info *li; 413267468Snon u_int8_t msg; 413367468Snon 413479697Snon#ifdef SCSI_LOW_DIAGNOSTIC 413579697Snon if (ti != slp->sl_Tnexus) 413679697Snon { 413779697Snon scsi_low_print(slp, NULL); 413879697Snon panic("scsi_low_msgin: Target nexus inconsistent"); 413979697Snon } 414079697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 414179697Snon 414267468Snon /* 414367468Snon * Phase changes, clear the pointer. 414467468Snon */ 414567468Snon if (ti->ti_ophase != ti->ti_phase) 414667468Snon { 414767468Snon MSGINPTR_CLR(ti); 414879697Snon ti->ti_msgin_parity_error = 0; 414979697Snon 415079697Snon slp->sl_ph_count ++; 415179697Snon if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES) 415279697Snon { 415379697Snon printf("%s: too many phase changes\n", slp->sl_xname); 415479697Snon slp->sl_error |= FATALIO; 415579697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 415679697Snon } 415767468Snon } 415867468Snon 415967468Snon /* 416067468Snon * Store a current messages byte into buffer and 416167468Snon * wait for the completion of the current msg. 416267468Snon */ 416379697Snon ti->ti_msgin[ti->ti_msginptr ++] = (u_int8_t) c; 416467468Snon if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN) 416567468Snon { 416667468Snon ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1; 416767468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); 416867468Snon } 416967468Snon 417067468Snon /* 417179697Snon * Check parity errors. 417279697Snon */ 417379697Snon if ((c & SCSI_LOW_DATA_PE) != 0) 417479697Snon { 417579697Snon ti->ti_msgin_parity_error ++; 417679697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0); 417779697Snon goto out; 417879697Snon } 417979697Snon 418079697Snon if (ti->ti_msgin_parity_error != 0) 418179697Snon goto out; 418279697Snon 418379697Snon /* 418467468Snon * Calculate messages length. 418567468Snon */ 418667468Snon msg = ti->ti_msgin[0]; 418767468Snon if (msg < MSGIN_DATA_LAST) 418867468Snon sdp = &scsi_low_msgin_data[msg]; 418967468Snon else 419067468Snon sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST]; 419167468Snon 419267468Snon if (ti->ti_msginlen == 0) 419367468Snon { 419467468Snon ti->ti_msginlen = sdp->md_len; 419567468Snon } 419667468Snon 419767468Snon /* 419867468Snon * Check comletion. 419967468Snon */ 420067468Snon if (ti->ti_msginptr < ti->ti_msginlen) 420179697Snon return EJUSTRETURN; 420267468Snon 420367468Snon /* 420467468Snon * Do process. 420567468Snon */ 420667468Snon if ((msg & MSG_IDENTIFY) == 0) 420767468Snon { 420879697Snon if (((*sdp->md_msgfunc) (slp)) == EJUSTRETURN) 420979697Snon return EJUSTRETURN; 421067468Snon } 421167468Snon else 421267468Snon { 421379697Snon li = slp->sl_Lnexus; 421467468Snon if (li == NULL) 421567468Snon { 421679697Snon li = scsi_low_alloc_li(ti, MSGCMD_LUN(msg), 0); 421767468Snon if (li == NULL) 421867468Snon goto badlun; 421979697Snon slp->sl_Lnexus = li; 422079697Snon (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp); 422167468Snon } 422279697Snon else 422379697Snon { 422479697Snon if (MSGCMD_LUN(msg) != li->li_lun) 422579697Snon goto badlun; 422679697Snon } 422767468Snon 422879697Snon if (slp->sl_Qnexus == NULL && li->li_nqio == 0) 422967468Snon { 423067468Snon if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG)) 423179697Snon { 423279697Snon#ifdef SCSI_LOW_DEBUG 423379697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0) 423479697Snon { 423579697Snon goto out; 423679697Snon } 423779697Snon#endif /* SCSI_LOW_DEBUG */ 423867468Snon goto badlun; 423979697Snon } 424067468Snon } 424167468Snon } 424279697Snon goto out; 424367468Snon 424467468Snon /* 424579697Snon * Msg process completed, reset msgin pointer and assert ATN if desired. 424667468Snon */ 424779697Snonbadlun: 424879697Snon slp->sl_error |= FATALIO; 424979697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); 425079697Snon SCSI_LOW_INFO(slp, ti, "MSGIN: identify wrong"); 425179697Snon 425279697Snonout: 425379697Snon if (ti->ti_msginptr < ti->ti_msginlen) 425479697Snon return EJUSTRETURN; 425579697Snon 425679697Snon#ifdef SCSI_LOW_DIAGNOSTIC 425779697Snon scsi_low_msg_log_write(&ti->ti_log_msgin, 425879697Snon &ti->ti_msgin[0], ti->ti_msginlen); 425979697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 426079697Snon 426179697Snon MSGINPTR_CLR(ti); 426279697Snon return 0; 426379697Snon} 426479697Snon 426579697Snon/********************************************************** 426679697Snon * disconnect 426779697Snon **********************************************************/ 426879697Snonint 426979697Snonscsi_low_disconnected(slp, ti) 427079697Snon struct scsi_low_softc *slp; 427179697Snon struct targ_info *ti; 427279697Snon{ 427379697Snon struct slccb *cb = slp->sl_Qnexus; 427479697Snon 427579697Snon /* check phase completion */ 427679697Snon switch (slp->sl_msgphase) 427767468Snon { 427879697Snon case MSGPH_RESET: 427979697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 428079697Snon scsi_low_msginfunc_cc(slp); 428179697Snon scsi_low_reset_nexus_target(slp, slp->sl_Tnexus, 0); 428279697Snon goto io_resume; 428367468Snon 428479697Snon case MSGPH_ABORT: 428579697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 428679697Snon scsi_low_msginfunc_cc(slp); 428779697Snon scsi_low_reset_nexus_lun(slp, slp->sl_Lnexus, 0); 428879697Snon goto io_resume; 428979697Snon 429079697Snon case MSGPH_TERM: 429179697Snon scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD); 429279697Snon scsi_low_msginfunc_cc(slp); 429379697Snon goto io_resume; 429479697Snon 429579697Snon case MSGPH_DISC: 429679697Snon if (cb != NULL) 429767468Snon { 429879697Snon struct lun_info *li; 429979697Snon 430079697Snon li = cb->li; 430179697Snon TAILQ_INSERT_TAIL(&li->li_discq, cb, ccb_chain); 430279697Snon cb->ccb_flags |= CCB_DISCQ; 430379697Snon cb->ccb_error |= slp->sl_error; 430479697Snon li->li_disc ++; 430579697Snon ti->ti_disc ++; 430679697Snon slp->sl_disc ++; 430779697Snon } 430879697Snon 430979697Snon#ifdef SCSI_LOW_STATICS 431079697Snon scsi_low_statics.nexus_disconnected ++; 431179697Snon#endif /* SCSI_LOW_STATICS */ 431279697Snon 431379697Snon#ifdef SCSI_LOW_DEBUG 431479697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DISC, ti->ti_id) != 0) 431579697Snon { 431679697Snon printf("## SCSI_LOW_DISCONNECTED ===============\n"); 431779697Snon scsi_low_print(slp, NULL); 431879697Snon } 431979697Snon#endif /* SCSI_LOW_DEBUG */ 432079697Snon break; 432179697Snon 432279697Snon case MSGPH_NULL: 432379697Snon slp->sl_error |= FATALIO; 432479697Snon if (ti->ti_phase == PH_SELSTART) 432579697Snon slp->sl_error |= SELTIMEOUTIO; 432679697Snon else 432779697Snon slp->sl_error |= UBFERR; 432879697Snon /* fall through */ 432979697Snon 433079697Snon case MSGPH_LCTERM: 433179697Snon case MSGPH_CMDC: 433279697Snonio_resume: 433379697Snon if (cb == NULL) 433479697Snon break; 433579697Snon 433679697Snon#ifdef SCSI_LOW_DEBUG 433779697Snon if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id)) 433879697Snon { 433979697Snon if (cb->ccb_omsgoutflag == SCSI_LOW_MSG_NOOP && 434079697Snon (cb->ccb_msgoutflag != 0 || 434179697Snon (ti->ti_msgflags & SCSI_LOW_MSG_NOOP))) 434279697Snon { 434379697Snon scsi_low_info(slp, ti, "ATTEN CHECK FAILED"); 434479697Snon } 434579697Snon } 434679697Snon#endif /* SCSI_LOW_DEBUG */ 434779697Snon 434879697Snon cb->ccb_error |= slp->sl_error; 434979697Snon if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY) 435079697Snon { 435179697Snon cb->ccb_flags |= CCB_STARTQ; 435279697Snon TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); 435379697Snon } 435479697Snon break; 435579697Snon } 435679697Snon 435779697Snon scsi_low_bus_release(slp, ti); 435879697Snon scsi_low_start(slp); 435979697Snon return 1; 436079697Snon} 436179697Snon 436279697Snon/********************************************************** 436379697Snon * TAG operations 436479697Snon **********************************************************/ 436579697Snonint 436679697Snonscsi_low_alloc_qtag(cb) 436779697Snon struct slccb *cb; 436879697Snon{ 436979697Snon struct lun_info *li = cb->li; 437079697Snon scsi_low_tag_t etag; 437179697Snon 437279697Snon if (cb->ccb_otag != SCSI_LOW_UNKTAG) 437379697Snon return 0; 437479697Snon 437579697Snon#ifndef SCSI_LOW_ALT_QTAG_ALLOCATE 437679697Snon etag = ffs(li->li_qtagbits); 437779697Snon if (etag == 0) 437879697Snon return ENOSPC; 437979697Snon 438079697Snon li->li_qtagbits &= ~(1 << (etag - 1)); 438179697Snon cb->ccb_otag = etag; 438279697Snon return 0; 438379697Snon 438479697Snon#else /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 438579697Snon for (etag = li->li_qd ; li->li_qd < SCSI_LOW_MAXNEXUS; li->li_qd ++) 438679697Snon if (li->li_qtagarray[li->li_qd] == 0) 438779697Snon goto found; 438879697Snon 438979697Snon for (li->li_qd = 0; li->li_qd < etag; li->li_qd ++) 439079697Snon if (li->li_qtagarray[li->li_qd] == 0) 439179697Snon goto found; 439279697Snon 439379697Snon return ENOSPC; 439479697Snon 439579697Snonfound: 439679697Snon li->li_qtagarray[li->li_qd] ++; 439779697Snon cb->ccb_otag = (li->li_qd ++); 439879697Snon return 0; 439979697Snon#endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 440079697Snon} 440179697Snon 440279697Snonint 440379697Snonscsi_low_dealloc_qtag(cb) 440479697Snon struct slccb *cb; 440579697Snon{ 440679697Snon struct lun_info *li = cb->li; 440779697Snon scsi_low_tag_t etag; 440879697Snon 440979697Snon if (cb->ccb_otag == SCSI_LOW_UNKTAG) 441079697Snon return 0; 441179697Snon 441279697Snon#ifndef SCSI_LOW_ALT_QTAG_ALLOCATE 441379697Snon etag = cb->ccb_otag - 1; 441467468Snon#ifdef SCSI_LOW_DIAGNOSTIC 441579697Snon if (etag >= sizeof(li->li_qtagbits) * NBBY) 441679697Snon panic("scsi_low_dealloc_tag: illegal tag"); 441767468Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 441879697Snon li->li_qtagbits |= (1 << etag); 441979697Snon 442079697Snon#else /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 442179697Snon etag = cb->ccb_otag; 442279697Snon#ifdef SCSI_LOW_DIAGNOSTIC 442379697Snon if (etag >= SCSI_LOW_MAXNEXUS) 442479697Snon panic("scsi_low_dealloc_tag: illegal tag"); 442579697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 442679697Snon li->li_qtagarray[etag] --; 442779697Snon#endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */ 442879697Snon 442979697Snon cb->ccb_otag = SCSI_LOW_UNKTAG; 443079697Snon return 0; 443179697Snon} 443279697Snon 443379697Snonstruct slccb * 443479697Snonscsi_low_revoke_ccb(slp, cb, fdone) 443579697Snon struct scsi_low_softc *slp; 443679697Snon struct slccb *cb; 443779697Snon int fdone; 443879697Snon{ 443979697Snon struct targ_info *ti = cb->ti; 444079697Snon struct lun_info *li = cb->li; 444179697Snon 444279697Snon#ifdef SCSI_LOW_DIAGNOSTIC 444379697Snon if ((cb->ccb_flags & (CCB_STARTQ | CCB_DISCQ)) == 444479697Snon (CCB_STARTQ | CCB_DISCQ)) 444579697Snon { 444679697Snon panic("%s: ccb in both queue\n", slp->sl_xname); 444767468Snon } 444879697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 444967468Snon 445079697Snon if ((cb->ccb_flags & CCB_STARTQ) != 0) 445179697Snon { 445279697Snon TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); 445379697Snon } 445479697Snon 445579697Snon if ((cb->ccb_flags & CCB_DISCQ) != 0) 445679697Snon { 445779697Snon TAILQ_REMOVE(&li->li_discq, cb, ccb_chain); 445879697Snon li->li_disc --; 445979697Snon ti->ti_disc --; 446079697Snon slp->sl_disc --; 446179697Snon } 446279697Snon 446379697Snon cb->ccb_flags &= ~(CCB_STARTQ | CCB_DISCQ | 446479697Snon CCB_SENSE | CCB_CLEARQ | CCB_INTERNAL); 446579697Snon 446679697Snon if (fdone != 0 && 446779697Snon (cb->ccb_rcnt ++ >= slp->sl_max_retry || 446879697Snon (cb->ccb_flags & CCB_NORETRY) != 0)) 446979697Snon { 447079697Snon cb->ccb_error |= FATALIO; 447179697Snon cb->ccb_flags &= ~CCB_AUTOSENSE; 447279697Snon if (scsi_low_done(slp, cb) != SCSI_LOW_DONE_COMPLETE) 447379697Snon panic("%s: done ccb retried\n", slp->sl_xname); 447479697Snon return NULL; 447579697Snon } 447679697Snon else 447779697Snon { 447879697Snon cb->ccb_error |= PENDINGIO; 447979697Snon scsi_low_deactivate_qtag(cb); 448079697Snon scsi_low_ccb_message_retry(cb); 448179697Snon cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; 448279697Snon return cb; 448379697Snon } 448467468Snon} 448567468Snon 448679697Snonvoid 448779697Snonscsi_low_reset_nexus_lun(slp, li, fdone) 448879697Snon struct scsi_low_softc *slp; 448979697Snon struct lun_info *li; 449079697Snon int fdone; 449179697Snon{ 449279697Snon struct slccb *cb, *ncb, *ecb; 449379697Snon 449479697Snon if (li == NULL) 449579697Snon return; 449679697Snon 449779697Snon ecb = NULL; 449879697Snon for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = ncb) 449979697Snon { 450079697Snon ncb = TAILQ_NEXT(cb, ccb_chain); 450179697Snon cb = scsi_low_revoke_ccb(slp, cb, fdone); 450279697Snon if (cb != NULL) 450379697Snon { 450479697Snon /* 450579697Snon * presumely keep ordering of io 450679697Snon */ 450779697Snon cb->ccb_flags |= CCB_STARTQ; 450879697Snon if (ecb == NULL) 450979697Snon { 451079697Snon TAILQ_INSERT_HEAD(&slp->sl_start,\ 451179697Snon cb, ccb_chain); 451279697Snon } 451379697Snon else 451479697Snon { 451579697Snon TAILQ_INSERT_AFTER(&slp->sl_start,\ 451679697Snon ecb, cb, ccb_chain); 451779697Snon } 451879697Snon ecb = cb; 451979697Snon } 452079697Snon } 452179697Snon} 452279697Snon 452367468Snon/************************************************************** 452467468Snon * Qurik setup 452567468Snon **************************************************************/ 452667468Snonstatic void 452779697Snonscsi_low_calcf_lun(li) 452867468Snon struct lun_info *li; 452967468Snon{ 453079697Snon struct targ_info *ti = li->li_ti; 453167468Snon struct scsi_low_softc *slp = ti->ti_sc; 453279697Snon u_int cfgflags, diskflags; 453367468Snon 453479697Snon if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID) 453579697Snon cfgflags = li->li_cfgflags; 453679697Snon else 453779697Snon cfgflags = 0; 453879697Snon 453979697Snon diskflags = li->li_diskflags & li->li_quirks; 454079697Snon 454179697Snon /* disconnect */ 454267468Snon li->li_flags &= ~SCSI_LOW_DISC; 454367468Snon if ((slp->sl_cfgflags & CFG_NODISC) == 0 && 454479697Snon (diskflags & SCSI_LOW_DISK_DISC) != 0 && 454579697Snon (cfgflags & SCSI_LOW_DISC) != 0) 454667468Snon li->li_flags |= SCSI_LOW_DISC; 454767468Snon 454879697Snon /* parity */ 454967468Snon li->li_flags |= SCSI_LOW_NOPARITY; 455067468Snon if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 && 455179697Snon (diskflags & SCSI_LOW_DISK_PARITY) != 0 && 455279697Snon (cfgflags & SCSI_LOW_NOPARITY) == 0) 455367468Snon li->li_flags &= ~SCSI_LOW_NOPARITY; 455467468Snon 455579697Snon /* qtag */ 455679697Snon if ((slp->sl_cfgflags & CFG_NOQTAG) == 0 && 455779697Snon (cfgflags & SCSI_LOW_QTAG) != 0 && 455879697Snon (diskflags & SCSI_LOW_DISK_QTAG) != 0) 455979697Snon { 456079697Snon li->li_flags |= SCSI_LOW_QTAG; 456179697Snon li->li_maxnexus = SCSI_LOW_MAXNEXUS; 456279697Snon li->li_maxnqio = li->li_maxnexus; 456379697Snon } 456479697Snon else 456579697Snon { 456679697Snon li->li_flags &= ~SCSI_LOW_QTAG; 456779697Snon li->li_maxnexus = 0; 456879697Snon li->li_maxnqio = li->li_maxnexus; 456979697Snon } 457079697Snon 457179697Snon /* cmd link */ 457279697Snon li->li_flags &= ~SCSI_LOW_LINK; 457379697Snon if ((cfgflags & SCSI_LOW_LINK) != 0 && 457479697Snon (diskflags & SCSI_LOW_DISK_LINK) != 0) 457579697Snon li->li_flags |= SCSI_LOW_LINK; 457679697Snon 457779697Snon /* compatible flags */ 457867468Snon li->li_flags &= ~SCSI_LOW_SYNC; 457979697Snon if (ti->ti_maxsynch.offset > 0) 458079697Snon li->li_flags |= SCSI_LOW_SYNC; 458179697Snon 458279697Snon#ifdef SCSI_LOW_DEBUG 458379697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0) 458467468Snon { 458579697Snon scsi_low_calcf_show(li); 458667468Snon } 458779697Snon#endif /* SCSI_LOW_DEBUG */ 458879697Snon} 458979697Snon 459079697Snonstatic void 459179697Snonscsi_low_calcf_target(ti) 459279697Snon struct targ_info *ti; 459379697Snon{ 459479697Snon struct scsi_low_softc *slp = ti->ti_sc; 459579697Snon u_int offset, period, diskflags; 459679697Snon 459779697Snon diskflags = ti->ti_diskflags & ti->ti_quirks; 459879697Snon 459979697Snon /* synch */ 460079697Snon if ((slp->sl_cfgflags & CFG_ASYNC) == 0 && 460179697Snon (diskflags & SCSI_LOW_DISK_SYNC) != 0) 460279697Snon { 460379697Snon offset = ti->ti_maxsynch.offset; 460479697Snon period = ti->ti_maxsynch.period; 460579697Snon if (offset == 0 || period == 0) 460679697Snon offset = period = 0; 460779697Snon } 460867468Snon else 460979697Snon { 461079697Snon offset = period = 0; 461179697Snon } 461267468Snon 461379697Snon ti->ti_maxsynch.offset = offset; 461479697Snon ti->ti_maxsynch.period = period; 461579697Snon 461679697Snon /* wide */ 461779697Snon if ((diskflags & SCSI_LOW_DISK_WIDE_32) == 0 && 461879697Snon ti->ti_width > SCSI_LOW_BUS_WIDTH_16) 461979697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_16; 462079697Snon 462179697Snon if ((diskflags & SCSI_LOW_DISK_WIDE_16) == 0 && 462279697Snon ti->ti_width > SCSI_LOW_BUS_WIDTH_8) 462379697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_8; 462479697Snon 462579697Snon if (ti->ti_flags_valid == SCSI_LOW_TARG_FLAGS_ALL_VALID) 462667468Snon { 462779697Snon if (ti->ti_maxsynch.offset != ti->ti_osynch.offset || 462879697Snon ti->ti_maxsynch.period != ti->ti_osynch.period) 462979697Snon ti->ti_setup_msg |= SCSI_LOW_MSG_SYNCH; 463079697Snon if (ti->ti_width != ti->ti_owidth) 463179697Snon ti->ti_setup_msg |= (SCSI_LOW_MSG_WIDE | SCSI_LOW_MSG_SYNCH); 463279697Snon 463379697Snon ti->ti_osynch = ti->ti_maxsynch; 463479697Snon ti->ti_owidth = ti->ti_width; 463567468Snon } 463667468Snon 463779697Snon#ifdef SCSI_LOW_DEBUG 463879697Snon if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0) 463979697Snon { 464079697Snon printf("%s(%d:*): max period(%dns) offset(%d) width(%d)\n", 464179697Snon slp->sl_xname, ti->ti_id, 464279697Snon ti->ti_maxsynch.period * 4, 464379697Snon ti->ti_maxsynch.offset, 464479697Snon ti->ti_width); 464579697Snon } 464679697Snon#endif /* SCSI_LOW_DEBUG */ 464767468Snon} 464867468Snon 464979697Snonstatic void 465079697Snonscsi_low_calcf_show(li) 465179697Snon struct lun_info *li; 465279697Snon{ 465379697Snon struct targ_info *ti = li->li_ti; 465479697Snon struct scsi_low_softc *slp = ti->ti_sc; 465579697Snon 465679697Snon printf("%s(%d:%d): period(%d ns) offset(%d) width(%d) flags 0x%b\n", 465779697Snon slp->sl_xname, ti->ti_id, li->li_lun, 465879697Snon ti->ti_maxsynch.period * 4, 465979697Snon ti->ti_maxsynch.offset, 466079697Snon ti->ti_width, 466179697Snon li->li_flags, SCSI_LOW_BITS); 466279697Snon} 466379697Snon 466479697Snon#ifdef SCSI_LOW_START_UP_CHECK 466579697Snon/************************************************************** 466679697Snon * scsi world start up 466779697Snon **************************************************************/ 466892770Salfredstatic int scsi_low_poll(struct scsi_low_softc *, struct slccb *); 466979697Snon 467067468Snonstatic int 467179697Snonscsi_low_start_up(slp) 467279697Snon struct scsi_low_softc *slp; 467367468Snon{ 467467468Snon struct targ_info *ti; 467567468Snon struct lun_info *li; 467679697Snon struct slccb *cb; 467779697Snon int target, lun; 467867468Snon 467979697Snon printf("%s: scsi_low: probing all devices ....\n", slp->sl_xname); 468067468Snon 468179697Snon for (target = 0; target < slp->sl_ntargs; target ++) 468279697Snon { 468379697Snon if (target == slp->sl_hostid) 468479697Snon { 468579697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 468679697Snon { 468779697Snon printf("%s: scsi_low: target %d (host card)\n", 468879697Snon slp->sl_xname, target); 468979697Snon } 469079697Snon continue; 469179697Snon } 469267468Snon 469379697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 469479697Snon { 469579697Snon printf("%s: scsi_low: target %d lun ", 469679697Snon slp->sl_xname, target); 469779697Snon } 469867468Snon 469979697Snon ti = slp->sl_ti[target]; 470079697Snon for (lun = 0; lun < slp->sl_nluns; lun ++) 470179697Snon { 470279697Snon if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL) 470379697Snon break; 470479697Snon 470579697Snon cb->osdep = NULL; 470679697Snon cb->bp = NULL; 470779697Snon 470879697Snon li = scsi_low_alloc_li(ti, lun, 1); 470979697Snon 471079697Snon scsi_low_enqueue(slp, ti, li, cb, 471179697Snon CCB_AUTOSENSE | CCB_POLLED, 0); 471279697Snon 471379697Snon scsi_low_poll(slp, cb); 471479697Snon 471579697Snon if (li->li_state != SCSI_LOW_LUN_OK) 471679697Snon break; 471779697Snon 471879697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 471979697Snon { 472079697Snon printf("%d ", lun); 472179697Snon } 472279697Snon } 472379697Snon 472479697Snon if ((slp->sl_show_result & SHOW_PROBE_RES) != 0) 472579697Snon { 472679697Snon printf("\n"); 472779697Snon } 472879697Snon } 472967468Snon return 0; 473067468Snon} 473167468Snon 473279697Snonstatic int 473379697Snonscsi_low_poll(slp, cb) 473479697Snon struct scsi_low_softc *slp; 473579697Snon struct slccb *cb; 473679697Snon{ 473779697Snon int tcount; 473879697Snon 473979697Snon tcount = 0; 474079697Snon while (slp->sl_nio > 0) 474179697Snon { 474279697Snon SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_POLL_HZ); 474379697Snon 474479697Snon (*slp->sl_funcs->scsi_low_poll) (slp); 474579697Snon if (tcount ++ < SCSI_LOW_POLL_HZ / SCSI_LOW_TIMEOUT_HZ) 474679697Snon continue; 474779697Snon 474879697Snon tcount = 0; 474979697Snon scsi_low_timeout_check(slp); 475079697Snon } 475179697Snon 475279697Snon return 0; 475379697Snon} 475479697Snon#endif /* SCSI_LOW_START_UP_CHECK */ 475579697Snon 475667468Snon/********************************************************** 475767468Snon * DEBUG SECTION 475867468Snon **********************************************************/ 475979697Snon#ifdef SCSI_LOW_DEBUG 476067468Snonstatic void 476179697Snonscsi_low_test_abort(slp, ti, li) 476279697Snon struct scsi_low_softc *slp; 476379697Snon struct targ_info *ti; 476479697Snon struct lun_info *li; 476579697Snon{ 476679697Snon struct slccb *acb; 476779697Snon 476879697Snon if (li->li_disc > 1) 476979697Snon { 477079697Snon acb = TAILQ_FIRST(&li->li_discq); 477179697Snon if (scsi_low_abort_ccb(slp, acb) == 0) 477279697Snon { 477379697Snon printf("%s: aborting ccb(0x%lx) start\n", 477479697Snon slp->sl_xname, (u_long) acb); 477579697Snon } 477679697Snon } 477779697Snon} 477879697Snon 477979697Snonstatic void 478079697Snonscsi_low_test_atten(slp, ti, msg) 478179697Snon struct scsi_low_softc *slp; 478279697Snon struct targ_info *ti; 478379697Snon u_int msg; 478479697Snon{ 478579697Snon 478679697Snon if (slp->sl_ph_count < SCSI_LOW_MAX_ATTEN_CHECK) 478779697Snon scsi_low_assert_msg(slp, ti, msg, 0); 478879697Snon else 478979697Snon printf("%s: atten check OK\n", slp->sl_xname); 479079697Snon} 479179697Snon 479279697Snonstatic void 479379697Snonscsi_low_test_cmdlnk(slp, cb) 479479697Snon struct scsi_low_softc *slp; 479579697Snon struct slccb *cb; 479679697Snon{ 479779697Snon#define SCSI_LOW_CMDLNK_NOK (CCB_INTERNAL | CCB_SENSE | CCB_CLEARQ) 479879697Snon 479979697Snon if ((cb->ccb_flags & SCSI_LOW_CMDLNK_NOK) != 0) 480079697Snon return; 480179697Snon 480279697Snon memcpy(cb->ccb_scsi_cmd, slp->sl_scp.scp_cmd, 480379697Snon slp->sl_scp.scp_cmdlen); 480479697Snon cb->ccb_scsi_cmd[slp->sl_scp.scp_cmdlen - 1] |= 1; 480579697Snon slp->sl_scp.scp_cmd = cb->ccb_scsi_cmd; 480679697Snon} 480779697Snon#endif /* SCSI_LOW_DEBUG */ 480879697Snon 480979697Snon/* static */ void 481067468Snonscsi_low_info(slp, ti, s) 481167468Snon struct scsi_low_softc *slp; 481267468Snon struct targ_info *ti; 481367468Snon u_char *s; 481467468Snon{ 481567468Snon 481679697Snon if (slp == NULL) 481779697Snon slp = LIST_FIRST(&sl_tab); 481879697Snon if (s == NULL) 481979697Snon s = "no message"; 482079697Snon 482179697Snon printf(">>>>> SCSI_LOW_INFO(0x%lx): %s\n", (u_long) slp->sl_Tnexus, s); 482267468Snon if (ti == NULL) 482367468Snon { 482479697Snon for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL; 482579697Snon ti = TAILQ_NEXT(ti, ti_chain)) 482679697Snon { 482767468Snon scsi_low_print(slp, ti); 482879697Snon } 482967468Snon } 483067468Snon else 483179697Snon { 483267468Snon scsi_low_print(slp, ti); 483379697Snon } 483467468Snon} 483567468Snon 483667468Snonstatic u_char *phase[] = 483767468Snon{ 483867468Snon "FREE", "ARBSTART", "SELSTART", "SELECTED", 483967468Snon "CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL" 484067468Snon}; 484167468Snon 484267468Snonvoid 484367468Snonscsi_low_print(slp, ti) 484467468Snon struct scsi_low_softc *slp; 484567468Snon struct targ_info *ti; 484667468Snon{ 484779697Snon struct lun_info *li; 484879697Snon struct slccb *cb; 484979697Snon struct sc_p *sp; 485067468Snon 485179697Snon if (ti == NULL || ti == slp->sl_Tnexus) 485279697Snon { 485379697Snon ti = slp->sl_Tnexus; 485479697Snon li = slp->sl_Lnexus; 485579697Snon cb = slp->sl_Qnexus; 485679697Snon } 485779697Snon else 485879697Snon { 485979697Snon li = LIST_FIRST(&ti->ti_litab); 486079697Snon cb = TAILQ_FIRST(&li->li_discq); 486179697Snon } 486279697Snon sp = &slp->sl_scp; 486367468Snon 486479697Snon printf("%s: === NEXUS T(0x%lx) L(0x%lx) Q(0x%lx) NIO(%d) ===\n", 486579697Snon slp->sl_xname, (u_long) ti, (u_long) li, (u_long) cb, 486679697Snon slp->sl_nio); 486767468Snon 486867468Snon /* target stat */ 486967468Snon if (ti != NULL) 487067468Snon { 487179697Snon u_int flags = 0, maxnqio = 0, nqio = 0; 487267468Snon int lun = -1; 487367468Snon 487467468Snon if (li != NULL) 487567468Snon { 487667468Snon lun = li->li_lun; 487767468Snon flags = li->li_flags; 487879697Snon maxnqio = li->li_maxnqio; 487979697Snon nqio = li->li_nqio; 488067468Snon } 488167468Snon 488279697Snon printf("%s(%d:%d) ph<%s> => ph<%s> DISC(%d) QIO(%d:%d)\n", 488379697Snon slp->sl_xname, 488467468Snon ti->ti_id, lun, phase[(int) ti->ti_ophase], 488579697Snon phase[(int) ti->ti_phase], ti->ti_disc, 488679697Snon nqio, maxnqio); 488767468Snon 488879697Snon if (cb != NULL) 488979697Snon { 489079697Snonprintf("CCB: cmd[0] 0x%x clen 0x%x dlen 0x%x<0x%x stat 0x%x err %b\n", 489179697Snon (u_int) cb->ccb_scp.scp_cmd[0], 489279697Snon cb->ccb_scp.scp_cmdlen, 489379697Snon cb->ccb_datalen, 489479697Snon cb->ccb_scp.scp_datalen, 489579697Snon (u_int) cb->ccb_sscp.scp_status, 489679697Snon cb->ccb_error, SCSI_LOW_ERRORBITS); 489779697Snon } 489867468Snon 489979697Snonprintf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] attention: %d\n", 490079697Snon (u_int) (ti->ti_msginptr), 490179697Snon (u_int) (ti->ti_msgin[0]), 490279697Snon (u_int) (ti->ti_msgin[1]), 490379697Snon (u_int) (ti->ti_msgin[2]), 490479697Snon (u_int) (ti->ti_msgin[3]), 490579697Snon (u_int) (ti->ti_msgin[4]), 490679697Snon slp->sl_atten); 490779697Snon 490867468Snonprintf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n", 490979697Snon (u_int) ti->ti_msgflags, 491079697Snon (u_int) (ti->ti_msgoutstr[0]), 491179697Snon (u_int) (ti->ti_msgoutstr[1]), 491279697Snon (u_int) (ti->ti_msgoutstr[2]), 491379697Snon (u_int) (ti->ti_msgoutstr[3]), 491479697Snon (u_int) (ti->ti_msgoutstr[4]), 491579697Snon ti->ti_msgoutlen, 491679697Snon flags, SCSI_LOW_BITS); 491767468Snon 491879697Snon#ifdef SCSI_LOW_DIAGNOSTIC 491979697Snon scsi_low_msg_log_show(&ti->ti_log_msgin, "MIN LOG ", 2); 492079697Snon scsi_low_msg_log_show(&ti->ti_log_msgout, "MOUT LOG", 2); 492179697Snon#endif /* SCSI_LOW_DIAGNOSTIC */ 492267468Snon 492367468Snon } 492479697Snon 492579697Snon printf("SCB: daddr 0x%lx dlen 0x%x stat 0x%x err %b\n", 492679697Snon (u_long) sp->scp_data, 492779697Snon sp->scp_datalen, 492879697Snon (u_int) sp->scp_status, 492979697Snon slp->sl_error, SCSI_LOW_ERRORBITS); 493067468Snon} 4931