summaryrefslogtreecommitdiffstats
path: root/sys/cam/scsi/scsi_low.c
diff options
context:
space:
mode:
authornon <non@FreeBSD.org>2001-07-14 00:38:51 +0000
committernon <non@FreeBSD.org>2001-07-14 00:38:51 +0000
commite91272502526170cc4f62c2357a8b7d3ee9b2c27 (patch)
tree01f4c48045db66f0e363a543a36a88e13470d6c9 /sys/cam/scsi/scsi_low.c
parenta67c5263965b3cce0db11089854bd6f3f56f2f8e (diff)
downloadFreeBSD-src-e91272502526170cc4f62c2357a8b7d3ee9b2c27.zip
FreeBSD-src-e91272502526170cc4f62c2357a8b7d3ee9b2c27.tar.gz
Catch up with NetBSD/pc98.
o Much cleanly separate NetBSD(XS) / FreeBSD(CAM) codes. o Improve tagged queing support (full QTAG). o Improve quirk support. o Improve parity error retry. o Impliment wide negotheation. o Cmd link support. o Add copyright of CAM part. o Change for CAM_NEW_TRAN_CODE. o Work around for buggy KME UJDCD450. o stg: add disconnet condition. o nsp: use suspend I/O. and more. I thank Honda-san. conf/options.pc98: add CT_USE_RELOCATE_OFFSET and CT_BUS_WEIGHT dev/{ct,ncv,nsp,stg}/*_{pccard,isa}.c: add splcam() before calling attach/detach functions. Tested by: bsd-nomads Obtained from: NetBSD/pc98
Diffstat (limited to 'sys/cam/scsi/scsi_low.c')
-rw-r--r--sys/cam/scsi/scsi_low.c4992
1 files changed, 3671 insertions, 1321 deletions
diff --git a/sys/cam/scsi/scsi_low.c b/sys/cam/scsi/scsi_low.c
index 2fd12ca..6099cd4 100644
--- a/sys/cam/scsi/scsi_low.c
+++ b/sys/cam/scsi/scsi_low.c
@@ -1,23 +1,35 @@
/* $FreeBSD$ */
-/* $NecBSD: scsi_low.c,v 1.24 1999/07/26 06:27:01 honda Exp $ */
+/* $NecBSD: scsi_low.c,v 1.24.10.8 2001/06/26 07:39:44 honda Exp $ */
/* $NetBSD$ */
#define SCSI_LOW_STATICS
-#define SCSI_LOW_WARNINGS
+#define SCSI_LOW_DEBUG
+#define SCSI_LOW_NEGOTIATE_BEFORE_SENSE
+#define SCSI_LOW_START_UP_CHECK
+
+/* #define SCSI_LOW_INFO_DETAIL */
+/* #define SCSI_LOW_QCLEAR_AFTER_CA */
+/* #define SCSI_LOW_FLAGS_QUIRKS_OK */
+
#ifdef __NetBSD__
#define SCSI_LOW_TARGET_OPEN
-#define SCSI_LOW_INFORM
-#endif
-#ifdef __FreeBSD__
-#define CAM
-#endif
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+#define SCSI_LOW_FLAGS_QUIRKS_OK
+#endif /* __FreeBSD__ */
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1995, 1996, 1997, 1998, 1999
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
- * Copyright (c) 1995, 1996, 1997, 1998, 1999
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
* Naofumi HONDA. All rights reserved.
+ *
+ * [Ported for FreeBSD CAM]
+ * Copyright (c) 2000, 2001
+ * MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -47,31 +59,32 @@
* When our host is reselected,
* nexus establish processes are little complicated.
* Normal steps are followings:
- * 1) Our host selected by target => target nexus (slp->sl_nexus)
- * 2) Identify msgin => lun nexus (ti->ti_li)
- * 3) Qtag msg => slccb nexus (ti->ti_nexus)
+ * 1) Our host selected by target => target nexus (slp->sl_Tnexus)
+ * 2) Identify msgin => lun nexus (slp->sl_Lnexus)
+ * 3) Qtag msg => ccb nexus (slp->sl_Qnexus)
*/
#include "opt_ddb.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#ifdef __NetBSD__
-#include <sys/disklabel.h>
-#endif
+
#ifdef __FreeBSD__
#if __FreeBSD_version >= 500001
#include <sys/bio.h>
+#else
+#include <machine/clock.h>
#endif
#include <sys/devicestat.h>
-#endif
+#endif /* __FreeBSD__ */
+
#include <sys/buf.h>
#include <sys/queue.h>
#include <sys/malloc.h>
-#include <sys/device_port.h>
#include <sys/errno.h>
-#ifdef __NetBSD__
+#ifdef __NetBSD__
+#include <sys/device.h>
#include <vm/vm.h>
#include <machine/bus.h>
@@ -85,9 +98,11 @@
#include <dev/scsipi/scsipi_disk.h>
#include <dev/scsipi/scsi_all.h>
#include <dev/scsipi/scsiconf.h>
+#include <sys/scsiio.h>
#include <i386/Cbus/dev/scsi_low.h>
-#endif
+#endif /* __NetBSD__ */
+
#ifdef __FreeBSD__
#include <cam/cam.h>
#include <cam/cam_ccb.h>
@@ -105,50 +120,80 @@
#else
#include <sys/cons.h>
#endif
-#define delay(time) DELAY(time)
+#endif /* __FreeBSD__ */
-/* from sys/dev/usb/usb_port.h
- XXX Change this when FreeBSD has memset
- */
-#define memset(d, v, s) \
- do{ \
- if ((v) == 0) \
- bzero((d), (s)); \
- else \
- panic("Non zero filler for memset, cannot handle!"); \
- } while (0)
-#endif
+/**************************************************************
+ * Constants
+ **************************************************************/
+#define SCSI_LOW_POLL_HZ 1000
+
+/* functions return values */
+#define SCSI_LOW_START_NO_QTAG 0
+#define SCSI_LOW_START_QTAG 1
#define SCSI_LOW_DONE_COMPLETE 0
#define SCSI_LOW_DONE_RETRY 1
+/* internal disk flags */
+#define SCSI_LOW_DISK_DISC 0x00000001
+#define SCSI_LOW_DISK_QTAG 0x00000002
+#define SCSI_LOW_DISK_LINK 0x00000004
+#define SCSI_LOW_DISK_PARITY 0x00000008
+#define SCSI_LOW_DISK_SYNC 0x00010000
+#define SCSI_LOW_DISK_WIDE_16 0x00020000
+#define SCSI_LOW_DISK_WIDE_32 0x00040000
+#define SCSI_LOW_DISK_WIDE (SCSI_LOW_DISK_WIDE_16 | SCSI_LOW_DISK_WIDE_32)
+#define SCSI_LOW_DISK_LFLAGS 0x0000ffff
+#define SCSI_LOW_DISK_TFLAGS 0xffff0000
+
+/**************************************************************
+ * Declarations
+ **************************************************************/
+/* static */ void scsi_low_info __P((struct scsi_low_softc *, struct targ_info *, u_char *));
static void scsi_low_engage __P((void *));
-static void scsi_low_info __P((struct scsi_low_softc *, struct targ_info *, u_char *));
-static void scsi_low_init_msgsys __P((struct scsi_low_softc *, struct targ_info *));
static struct slccb *scsi_low_establish_ccb __P((struct targ_info *, struct lun_info *, scsi_low_tag_t));
static int scsi_low_done __P((struct scsi_low_softc *, struct slccb *));
+static int scsi_low_setup_done __P((struct scsi_low_softc *, struct slccb *));
+static void scsi_low_bus_release __P((struct scsi_low_softc *, struct targ_info *));
static void scsi_low_twiddle_wait __P((void));
static struct lun_info *scsi_low_alloc_li __P((struct targ_info *, int, int));
-static struct targ_info *scsi_low_alloc_ti __P((struct scsi_low_softc *, int, int));
-static void scsi_low_calcf __P((struct targ_info *, struct lun_info *));
-static struct lun_info *scsi_low_establish_lun __P((struct targ_info *, int));
-#ifndef CAM
-static void scsi_low_scsi_minphys __P((struct buf *));
-#endif
-#ifdef SCSI_LOW_TARGET_OPEN
-static int scsi_low_target_open __P((struct scsipi_link *, struct cfdata *));
-#endif /* SCSI_LOW_TARGET_OPEN */
-#ifdef CAM
-void scsi_low_scsi_action(struct cam_sim *sim, union ccb *ccb);
-static void scsi_low_poll (struct cam_sim *sim);
-#else
-static int scsi_low_scsi_cmd __P((struct scsipi_xfer *));
-#endif
+static struct targ_info *scsi_low_alloc_ti __P((struct scsi_low_softc *, int));
+static void scsi_low_calcf_lun __P((struct lun_info *));
+static void scsi_low_calcf_target __P((struct targ_info *));
+static void scsi_low_calcf_show __P((struct lun_info *));
static void scsi_low_reset_nexus __P((struct scsi_low_softc *, int));
+static void scsi_low_reset_nexus_target __P((struct scsi_low_softc *, struct targ_info *, int));
+static void scsi_low_reset_nexus_lun __P((struct scsi_low_softc *, struct lun_info *, int));
static int scsi_low_init __P((struct scsi_low_softc *, u_int));
static void scsi_low_start __P((struct scsi_low_softc *));
static void scsi_low_free_ti __P((struct scsi_low_softc *));
-static void scsi_low_clear_ccb __P((struct slccb *));
+
+static int scsi_low_alloc_qtag __P((struct slccb *));
+static int scsi_low_dealloc_qtag __P((struct slccb *));
+static int scsi_low_enqueue __P((struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *, u_int, u_int));
+static int scsi_low_message_enqueue __P((struct scsi_low_softc *, struct targ_info *, struct lun_info *, u_int));
+static void scsi_low_unit_ready_cmd __P((struct slccb *));
+static void scsi_low_timeout __P((void *));
+static int scsi_low_timeout_check __P((struct scsi_low_softc *));
+#ifdef SCSI_LOW_START_UP_CHECK
+static int scsi_low_start_up __P((struct scsi_low_softc *));
+#endif /* SCSI_LOW_START_UP_CHECK */
+static int scsi_low_abort_ccb __P((struct scsi_low_softc *, struct slccb *));
+static struct slccb *scsi_low_revoke_ccb __P((struct scsi_low_softc *, struct slccb *, int));
+
+int scsi_low_version_major = 2;
+int scsi_low_version_minor = 17;
+
+static struct scsi_low_softc_tab sl_tab = LIST_HEAD_INITIALIZER(sl_tab);
+
+/**************************************************************
+ * Debug, Run test and Statics
+ **************************************************************/
+#ifdef SCSI_LOW_INFO_DETAIL
+#define SCSI_LOW_INFO(slp, ti, s) scsi_low_info((slp), (ti), (s))
+#else /* !SCSI_LOW_INFO_DETAIL */
+#define SCSI_LOW_INFO(slp, ti, s) printf("%s: %s\n", (slp)->sl_xname, (s))
+#endif /* !SCSI_LOW_INFO_DETAIL */
#ifdef SCSI_LOW_STATICS
struct scsi_low_statics {
@@ -159,6 +204,1517 @@ struct scsi_low_statics {
int nexus_conflict;
} scsi_low_statics;
#endif /* SCSI_LOW_STATICS */
+
+#ifdef SCSI_LOW_DEBUG
+#define SCSI_LOW_DEBUG_DONE 0x00001
+#define SCSI_LOW_DEBUG_DISC 0x00002
+#define SCSI_LOW_DEBUG_SENSE 0x00004
+#define SCSI_LOW_DEBUG_CALCF 0x00008
+#define SCSI_LOW_DEBUG_ACTION 0x10000
+int scsi_low_debug = 0;
+
+#define SCSI_LOW_MAX_ATTEN_CHECK 32
+#define SCSI_LOW_ATTEN_CHECK 0x0001
+#define SCSI_LOW_CMDLNK_CHECK 0x0002
+#define SCSI_LOW_ABORT_CHECK 0x0004
+#define SCSI_LOW_NEXUS_CHECK 0x0008
+int scsi_low_test = 0;
+int scsi_low_test_id = 0;
+
+static void scsi_low_test_abort __P((struct scsi_low_softc *, struct targ_info *, struct lun_info *));
+static void scsi_low_test_cmdlnk __P((struct scsi_low_softc *, struct slccb *));
+static void scsi_low_test_atten __P((struct scsi_low_softc *, struct targ_info *, u_int));
+#define SCSI_LOW_DEBUG_TEST_GO(fl, id) \
+ ((scsi_low_test & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
+#define SCSI_LOW_DEBUG_GO(fl, id) \
+ ((scsi_low_debug & (fl)) != 0 && (scsi_low_test_id & (1 << (id))) == 0)
+#endif /* SCSI_LOW_DEBUG */
+
+/**************************************************************
+ * CCB
+ **************************************************************/
+GENERIC_CCB_STATIC_ALLOC(scsi_low, slccb)
+GENERIC_CCB(scsi_low, slccb, ccb_chain)
+
+/**************************************************************
+ * Inline functions
+ **************************************************************/
+#define SCSI_LOW_INLINE static __inline
+SCSI_LOW_INLINE void scsi_low_activate_qtag __P((struct slccb *));
+SCSI_LOW_INLINE void scsi_low_deactivate_qtag __P((struct slccb *));
+SCSI_LOW_INLINE void scsi_low_ccb_message_assert __P((struct slccb *, u_int));
+SCSI_LOW_INLINE void scsi_low_ccb_message_exec __P((struct scsi_low_softc *, struct slccb *));
+SCSI_LOW_INLINE void scsi_low_ccb_message_retry __P((struct slccb *));
+SCSI_LOW_INLINE void scsi_low_ccb_message_clear __P((struct slccb *));
+SCSI_LOW_INLINE void scsi_low_init_msgsys __P((struct scsi_low_softc *, struct targ_info *));
+
+SCSI_LOW_INLINE void
+scsi_low_activate_qtag(cb)
+ struct slccb *cb;
+{
+ struct lun_info *li = cb->li;
+
+ if (cb->ccb_tag != SCSI_LOW_UNKTAG)
+ return;
+
+ li->li_nqio ++;
+ cb->ccb_tag = cb->ccb_otag;
+}
+
+SCSI_LOW_INLINE void
+scsi_low_deactivate_qtag(cb)
+ struct slccb *cb;
+{
+ struct lun_info *li = cb->li;
+
+ if (cb->ccb_tag == SCSI_LOW_UNKTAG)
+ return;
+
+ li->li_nqio --;
+ cb->ccb_tag = SCSI_LOW_UNKTAG;
+}
+
+SCSI_LOW_INLINE void
+scsi_low_ccb_message_exec(slp, cb)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+{
+
+ scsi_low_assert_msg(slp, cb->ti, cb->ccb_msgoutflag, 0);
+ cb->ccb_msgoutflag = 0;
+}
+
+SCSI_LOW_INLINE void
+scsi_low_ccb_message_assert(cb, msg)
+ struct slccb *cb;
+ u_int msg;
+{
+
+ cb->ccb_msgoutflag = cb->ccb_omsgoutflag = msg;
+}
+
+SCSI_LOW_INLINE void
+scsi_low_ccb_message_retry(cb)
+ struct slccb *cb;
+{
+ cb->ccb_msgoutflag = cb->ccb_omsgoutflag;
+}
+
+SCSI_LOW_INLINE void
+scsi_low_ccb_message_clear(cb)
+ struct slccb *cb;
+{
+ cb->ccb_msgoutflag = 0;
+}
+
+SCSI_LOW_INLINE void
+scsi_low_init_msgsys(slp, ti)
+ struct scsi_low_softc *slp;
+ struct targ_info *ti;
+{
+
+ ti->ti_msginptr = 0;
+ ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0;
+ SCSI_LOW_DEASSERT_ATN(slp);
+ SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL);
+}
+
+/*=============================================================
+ * START OF OS switch (All OS depend fucntions should be here)
+ =============================================================*/
+/* common os depend utitlities */
+#define SCSI_LOW_CMD_RESIDUAL_CHK 0x0001
+#define SCSI_LOW_CMD_ORDERED_QTAG 0x0002
+#define SCSI_LOW_CMD_ABORT_WARNING 0x0004
+
+static u_int8_t scsi_low_cmd_flags[256] = {
+/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+/*0*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0,
+/*1*/ 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
+/*2*/ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 5, 5,
+/*3*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5,
+};
+
+struct scsi_low_error_code {
+ int error_bits;
+ int error_code;
+};
+
+static struct slccb *scsi_low_find_ccb __P((struct scsi_low_softc *, u_int, u_int, void *));
+static int scsi_low_translate_error_code __P((struct slccb *, struct scsi_low_error_code *));
+
+static struct slccb *
+scsi_low_find_ccb(slp, target, lun, osdep)
+ struct scsi_low_softc *slp;
+ u_int target, lun;
+ void *osdep;
+{
+ struct targ_info *ti;
+ struct lun_info *li;
+ struct slccb *cb;
+
+ ti = slp->sl_ti[target];
+ li = scsi_low_alloc_li(ti, lun, 0);
+ if (li == NULL)
+ return NULL;
+
+ if ((cb = slp->sl_Qnexus) != NULL && cb->osdep == osdep)
+ return cb;
+
+ for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL;
+ cb = TAILQ_NEXT(cb, ccb_chain))
+ {
+ if (cb->osdep == osdep)
+ return cb;
+ }
+
+ for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL;
+ cb = TAILQ_NEXT(cb, ccb_chain))
+ {
+ if (cb->osdep == osdep)
+ return cb;
+ }
+ return NULL;
+}
+
+static int
+scsi_low_translate_error_code(cb, tp)
+ struct slccb *cb;
+ struct scsi_low_error_code *tp;
+{
+
+ if (cb->ccb_error == 0)
+ return tp->error_code;
+
+ for (tp ++; (cb->ccb_error & tp->error_bits) == 0; tp ++)
+ ;
+ return tp->error_code;
+}
+
+#ifdef SCSI_LOW_INTERFACE_XS
+/**************************************************************
+ * SCSI INTERFACE (XS)
+ **************************************************************/
+#define SCSI_LOW_MINPHYS 0x10000
+#define SCSI_LOW_MALLOC(size) malloc((size), M_DEVBUF, M_NOWAIT)
+#define SCSI_LOW_FREE(pt) free((pt), M_DEVBUF)
+#define SCSI_LOW_ALLOC_CCB(flags) scsi_low_get_ccb((flags))
+#define SCSI_LOW_XS_POLL_HZ 1000
+
+static int scsi_low_poll_xs __P((struct scsi_low_softc *, struct slccb *));
+static void scsi_low_scsi_minphys_xs __P((struct buf *));
+#ifdef SCSI_LOW_TARGET_OPEN
+static int scsi_low_target_open __P((struct scsipi_link *, struct cfdata *));
+#endif /* SCSI_LOW_TARGET_OPEN */
+static int scsi_low_scsi_cmd_xs __P((struct scsipi_xfer *));
+static int scsi_low_enable_xs __P((void *, int));
+static int scsi_low_ioctl_xs __P((struct scsipi_link *, u_long, caddr_t, int, struct proc *));
+
+static int scsi_low_attach_xs __P((struct scsi_low_softc *));
+static int scsi_low_world_start_xs __P((struct scsi_low_softc *));
+static int scsi_low_dettach_xs __P((struct scsi_low_softc *));
+static int scsi_low_ccb_setup_xs __P((struct scsi_low_softc *, struct slccb *));
+static int scsi_low_done_xs __P((struct scsi_low_softc *, struct slccb *));
+static void scsi_low_timeout_xs __P((struct scsi_low_softc *, int, int));
+static u_int scsi_low_translate_quirks_xs __P((u_int));
+static void scsi_low_setup_quirks_xs __P((struct targ_info *, struct lun_info *, u_int));
+
+struct scsi_low_osdep_funcs scsi_low_osdep_funcs_xs = {
+ scsi_low_attach_xs,
+ scsi_low_world_start_xs,
+ scsi_low_dettach_xs,
+ scsi_low_ccb_setup_xs,
+ scsi_low_done_xs,
+ scsi_low_timeout_xs
+};
+
+struct scsipi_device scsi_low_dev = {
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+};
+
+struct scsi_low_error_code scsi_low_error_code_xs[] = {
+ {0, XS_NOERROR},
+ {SENSEIO, XS_SENSE},
+ {BUSYERR, XS_BUSY },
+ {SELTIMEOUTIO, XS_SELTIMEOUT},
+ {TIMEOUTIO, XS_TIMEOUT},
+ {-1, XS_DRIVER_STUFFUP}
+};
+
+static int
+scsi_low_ioctl_xs(link, cmd, addr, flag, p)
+ struct scsipi_link *link;
+ u_long cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ struct scsi_low_softc *slp;
+ int s, error = ENOTTY;
+
+ slp = (struct scsi_low_softc *) link->adapter_softc;
+ if ((slp->sl_flags & HW_INACTIVE) != 0)
+ return ENXIO;
+
+ if (cmd == SCBUSIORESET)
+ {
+ s = SCSI_LOW_SPLSCSI();
+ scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL);
+ splx(s);
+ error = 0;
+ }
+ else if (slp->sl_funcs->scsi_low_ioctl != 0)
+ {
+ error = (*slp->sl_funcs->scsi_low_ioctl)
+ (slp, cmd, addr, flag, p);
+ }
+
+ return error;
+}
+
+static int
+scsi_low_enable_xs(arg, enable)
+ void *arg;
+ int enable;
+{
+ struct scsi_low_softc *slp = arg;
+
+ if (enable != 0)
+ {
+ if ((slp->sl_flags & HW_INACTIVE) != 0)
+ return ENXIO;
+ }
+ else
+ {
+ if ((slp->sl_flags & HW_INACTIVE) != 0 ||
+ (slp->sl_flags & HW_POWERCTRL) == 0)
+ return 0;
+
+ slp->sl_flags |= HW_POWDOWN;
+ if (slp->sl_funcs->scsi_low_power != NULL)
+ {
+ (*slp->sl_funcs->scsi_low_power)
+ (slp, SCSI_LOW_POWDOWN);
+ }
+ }
+ return 0;
+}
+
+static void
+scsi_low_scsi_minphys_xs(bp)
+ struct buf *bp;
+{
+
+ if (bp->b_bcount > SCSI_LOW_MINPHYS)
+ bp->b_bcount = SCSI_LOW_MINPHYS;
+ minphys(bp);
+}
+
+static int
+scsi_low_poll_xs(slp, cb)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+{
+ struct scsipi_xfer *xs = cb->osdep;
+ int tcount;
+
+ cb->ccb_flags |= CCB_NOSDONE;
+ tcount = 0;
+
+ while (slp->sl_nio > 0)
+ {
+ SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_XS_POLL_HZ);
+
+ (*slp->sl_funcs->scsi_low_poll) (slp);
+
+ if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0)
+ {
+ cb->ccb_flags |= CCB_NORETRY;
+ cb->ccb_error |= FATALIO;
+ (void) scsi_low_revoke_ccb(slp, cb, 1);
+ printf("%s: hardware inactive in poll mode\n",
+ slp->sl_xname);
+ }
+
+ if ((xs->flags & ITSDONE) != 0)
+ break;
+
+ if (tcount ++ < SCSI_LOW_XS_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
+ continue;
+
+ tcount = 0;
+ scsi_low_timeout_check(slp);
+ }
+
+ xs->flags |= ITSDONE;
+ scsipi_done(xs);
+ return COMPLETE;
+}
+
+static int
+scsi_low_scsi_cmd_xs(xs)
+ struct scsipi_xfer *xs;
+{
+ struct scsipi_link *splp = xs->sc_link;
+ struct scsi_low_softc *slp = splp->adapter_softc;
+ struct targ_info *ti;
+ struct lun_info *li;
+ struct slccb *cb;
+ int s, targ, lun, flags, rv;
+
+ if ((cb = SCSI_LOW_ALLOC_CCB(xs->flags & SCSI_NOSLEEP)) == NULL)
+ return TRY_AGAIN_LATER;
+
+ targ = splp->scsipi_scsi.target,
+ lun = splp->scsipi_scsi.lun;
+ ti = slp->sl_ti[targ];
+
+ cb->osdep = xs;
+ cb->bp = xs->bp;
+
+ if ((xs->flags & SCSI_POLL) == 0)
+ flags = CCB_AUTOSENSE;
+ else
+ flags = CCB_AUTOSENSE | CCB_POLLED;
+
+
+ s = SCSI_LOW_SPLSCSI();
+ li = scsi_low_alloc_li(ti, lun, 1);
+ if ((u_int) splp->quirks != li->li_sloi.sloi_quirks)
+ {
+ scsi_low_setup_quirks_xs(ti, li, (u_int) splp->quirks);
+ }
+
+ if ((xs->flags & SCSI_RESET) != 0)
+ {
+ flags |= CCB_NORETRY | CCB_URGENT;
+ scsi_low_enqueue(slp, ti, li, cb, flags, SCSI_LOW_MSG_RESET);
+ }
+ else
+ {
+ if (ti->ti_setup_msg != 0)
+ {
+ scsi_low_message_enqueue(slp, ti, li, flags);
+ }
+
+ flags |= CCB_SCSIIO;
+ scsi_low_enqueue(slp, ti, li, cb, flags, 0);
+ }
+
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, ti->ti_id) != 0)
+ {
+ scsi_low_test_abort(slp, ti, li);
+ }
+#endif /* SCSI_LOW_DEBUG */
+
+ if ((cb->ccb_flags & CCB_POLLED) != 0)
+ {
+ rv = scsi_low_poll_xs(slp, cb);
+ }
+ else
+ {
+ rv = SUCCESSFULLY_QUEUED;
+ }
+ splx(s);
+ return rv;
+}
+
+static int
+scsi_low_attach_xs(slp)
+ struct scsi_low_softc *slp;
+{
+ struct scsipi_adapter *sap;
+ struct scsipi_link *splp;
+
+ strncpy(slp->sl_xname, slp->sl_dev.dv_xname, 16);
+
+ sap = SCSI_LOW_MALLOC(sizeof(*sap));
+ if (sap == NULL)
+ return ENOMEM;
+ splp = SCSI_LOW_MALLOC(sizeof(*splp));
+ if (splp == NULL)
+ return ENOMEM;
+
+ SCSI_LOW_BZERO(sap, sizeof(*sap));
+ SCSI_LOW_BZERO(splp, sizeof(*splp));
+
+ sap->scsipi_cmd = scsi_low_scsi_cmd_xs;
+ sap->scsipi_minphys = scsi_low_scsi_minphys_xs;
+ sap->scsipi_enable = scsi_low_enable_xs;
+ sap->scsipi_ioctl = scsi_low_ioctl_xs;
+#ifdef SCSI_LOW_TARGET_OPEN
+ sap->open_target_lu = scsi_low_target_open;
+#endif /* SCSI_LOW_TARGET_OPEN */
+
+ splp->adapter_softc = slp;
+ splp->scsipi_scsi.adapter_target = slp->sl_hostid;
+ splp->scsipi_scsi.max_target = slp->sl_ntargs - 1;
+ splp->scsipi_scsi.max_lun = slp->sl_nluns - 1;
+ splp->scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
+ splp->openings = slp->sl_openings;
+ splp->type = BUS_SCSI;
+ splp->adapter_softc = slp;
+ splp->adapter = sap;
+ splp->device = &scsi_low_dev;
+
+ slp->sl_si.si_splp = splp;
+ slp->sl_show_result = SHOW_ALL_NEG;
+ return 0;
+}
+
+static int
+scsi_low_world_start_xs(slp)
+ struct scsi_low_softc *slp;
+{
+
+ return 0;
+}
+
+static int
+scsi_low_dettach_xs(slp)
+ struct scsi_low_softc *slp;
+{
+
+ /*
+ * scsipi does not have dettach bus fucntion.
+ *
+ scsipi_dettach_scsibus(slp->sl_si.si_splp);
+ */
+ return 0;
+}
+
+static int
+scsi_low_ccb_setup_xs(slp, cb)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+{
+ struct scsipi_xfer *xs = (struct scsipi_xfer *) cb->osdep;
+
+ if ((cb->ccb_flags & CCB_SCSIIO) != 0)
+ {
+ cb->ccb_scp.scp_cmd = (u_int8_t *) xs->cmd;
+ cb->ccb_scp.scp_cmdlen = xs->cmdlen;
+ cb->ccb_scp.scp_data = xs->data;
+ cb->ccb_scp.scp_datalen = xs->datalen;
+ cb->ccb_scp.scp_direction = (xs->flags & SCSI_DATA_OUT) ?
+ SCSI_LOW_WRITE : SCSI_LOW_READ;
+ cb->ccb_tcmax = xs->timeout / 1000;
+ }
+ else
+ {
+ scsi_low_unit_ready_cmd(cb);
+ }
+ return SCSI_LOW_START_QTAG;
+}
+
+static int
+scsi_low_done_xs(slp, cb)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+{
+ struct scsipi_xfer *xs;
+
+ xs = (struct scsipi_xfer *) cb->osdep;
+ if (cb->ccb_error == 0)
+ {
+ xs->error = XS_NOERROR;
+ xs->resid = 0;
+ }
+ else
+ {
+ if (cb->ccb_rcnt >= slp->sl_max_retry)
+ cb->ccb_error |= ABORTIO;
+
+ if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
+ (cb->ccb_error & ABORTIO) == 0)
+ return EJUSTRETURN;
+
+ if ((cb->ccb_error & SENSEIO) != 0)
+ {
+ xs->sense.scsi_sense = cb->ccb_sense;
+ }
+
+ xs->error = scsi_low_translate_error_code(cb,
+ &scsi_low_error_code_xs[0]);
+
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if ((cb->ccb_flags & CCB_SILENT) == 0 &&
+ cb->ccb_scp.scp_cmdlen > 0 &&
+ (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
+ SCSI_LOW_CMD_ABORT_WARNING) != 0)
+ {
+ printf("%s: WARNING: scsi_low IO abort\n",
+ slp->sl_xname);
+ scsi_low_print(slp, NULL);
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+ }
+
+ if (cb->ccb_scp.scp_status == ST_UNKNOWN)
+ xs->status = 0; /* XXX */
+ else
+ xs->status = cb->ccb_scp.scp_status;
+
+ xs->flags |= ITSDONE;
+ if ((cb->ccb_flags & CCB_NOSDONE) == 0)
+ scsipi_done(xs);
+
+ return 0;
+}
+
+static void
+scsi_low_timeout_xs(slp, ch, action)
+ struct scsi_low_softc *slp;
+ int ch;
+ int action;
+{
+
+ switch (ch)
+ {
+ case SCSI_LOW_TIMEOUT_CH_IO:
+ switch (action)
+ {
+ case SCSI_LOW_TIMEOUT_START:
+ timeout(scsi_low_timeout, slp,
+ hz / SCSI_LOW_TIMEOUT_HZ);
+ break;
+ case SCSI_LOW_TIMEOUT_STOP:
+ untimeout(scsi_low_timeout, slp);
+ break;
+ }
+ break;
+
+ case SCSI_LOW_TIMEOUT_CH_ENGAGE:
+ switch (action)
+ {
+ case SCSI_LOW_TIMEOUT_START:
+ timeout(scsi_low_engage, slp, 1);
+ break;
+ case SCSI_LOW_TIMEOUT_STOP:
+ untimeout(scsi_low_engage, slp);
+ break;
+ }
+ break;
+
+ case SCSI_LOW_TIMEOUT_CH_RECOVER:
+ break;
+ }
+}
+
+u_int
+scsi_low_translate_quirks_xs(quirks)
+ u_int quirks;
+{
+ u_int flags;
+
+ flags = SCSI_LOW_DISK_LFLAGS | SCSI_LOW_DISK_TFLAGS;
+
+#ifdef SDEV_NODISC
+ if (quirks & SDEV_NODISC)
+ flags &= ~SCSI_LOW_DISK_DISC;
+#endif /* SDEV_NODISC */
+#ifdef SDEV_NOPARITY
+ if (quirks & SDEV_NOPARITY)
+ flags &= ~SCSI_LOW_DISK_PARITY;
+#endif /* SDEV_NOPARITY */
+#ifdef SDEV_NOCMDLNK
+ if (quirks & SDEV_NOCMDLNK)
+ flags &= ~SCSI_LOW_DISK_LINK;
+#endif /* SDEV_NOCMDLNK */
+#ifdef SDEV_NOTAG
+ if (quirks & SDEV_NOTAG)
+ flags &= ~SCSI_LOW_DISK_QTAG;
+#endif /* SDEV_NOTAG */
+#ifdef SDEV_NOSYNC
+ if (quirks & SDEV_NOSYNC)
+ flags &= ~SCSI_LOW_DISK_SYNC;
+#endif /* SDEV_NOSYNC */
+
+ return flags;
+}
+
+static void
+scsi_low_setup_quirks_xs(ti, li, flags)
+ struct targ_info *ti;
+ struct lun_info *li;
+ u_int flags;
+{
+ u_int quirks;
+
+ li->li_sloi.sloi_quirks = flags;
+ quirks = scsi_low_translate_quirks_xs(flags);
+ ti->ti_quirks = quirks & SCSI_LOW_DISK_TFLAGS;
+ li->li_quirks = quirks & SCSI_LOW_DISK_LFLAGS;
+ ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
+ li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
+ scsi_low_calcf_target(ti);
+ scsi_low_calcf_lun(li);
+ scsi_low_calcf_show(li);
+}
+
+#ifdef SCSI_LOW_TARGET_OPEN
+static int
+scsi_low_target_open(link, cf)
+ struct scsipi_link *link;
+ struct cfdata *cf;
+{
+ u_int target = link->scsipi_scsi.target;
+ u_int lun = link->scsipi_scsi.lun;
+ struct scsi_low_softc *slp;
+ struct targ_info *ti;
+ struct lun_info *li;
+
+ slp = (struct scsi_low_softc *) link->adapter_softc;
+ ti = slp->sl_ti[target];
+ li = scsi_low_alloc_li(ti, lun, 0);
+ if (li == NULL)
+ return 0;
+
+ li->li_cfgflags = cf->cf_flags;
+ scsi_low_setup_quirks_xs(ti, li, (u_int) link->quirks);
+ return 0;
+}
+#endif /* SCSI_LOW_TARGET_OPEN */
+
+#endif /* SCSI_LOW_INTERFACE_XS */
+
+#ifdef SCSI_LOW_INTERFACE_CAM
+/**************************************************************
+ * SCSI INTERFACE (CAM)
+ **************************************************************/
+#define SCSI_LOW_MALLOC(size) malloc((size), M_DEVBUF, M_NOWAIT)
+#define SCSI_LOW_FREE(pt) free((pt), M_DEVBUF)
+#define SCSI_LOW_ALLOC_CCB(flags) scsi_low_get_ccb()
+
+static void scsi_low_poll_cam __P((struct cam_sim *));
+static void scsi_low_cam_rescan_callback __P((struct cam_periph *, union ccb *));
+static void scsi_low_rescan_bus_cam __P((struct scsi_low_softc *));
+void scsi_low_scsi_action_cam __P((struct cam_sim *, union ccb *));
+
+static int scsi_low_attach_cam __P((struct scsi_low_softc *));
+static int scsi_low_world_start_cam __P((struct scsi_low_softc *));
+static int scsi_low_dettach_cam __P((struct scsi_low_softc *));
+static int scsi_low_ccb_setup_cam __P((struct scsi_low_softc *, struct slccb *));
+static int scsi_low_done_cam __P((struct scsi_low_softc *, struct slccb *));
+static void scsi_low_timeout_cam __P((struct scsi_low_softc *, int, int));
+
+struct scsi_low_osdep_funcs scsi_low_osdep_funcs_cam = {
+ scsi_low_attach_cam,
+ scsi_low_world_start_cam,
+ scsi_low_dettach_cam,
+ scsi_low_ccb_setup_cam,
+ scsi_low_done_cam,
+ scsi_low_timeout_cam
+};
+
+struct scsi_low_error_code scsi_low_error_code_cam[] = {
+ {0, CAM_REQ_CMP},
+ {SENSEIO, CAM_AUTOSNS_VALID | CAM_REQ_CMP_ERR},
+ {SENSEERR, CAM_AUTOSENSE_FAIL},
+ {UACAERR, CAM_SCSI_STATUS_ERROR},
+ {BUSYERR | STATERR, CAM_SCSI_STATUS_ERROR},
+ {SELTIMEOUTIO, CAM_SEL_TIMEOUT},
+ {TIMEOUTIO, CAM_CMD_TIMEOUT},
+ {PDMAERR, CAM_DATA_RUN_ERR},
+ {PARITYERR, CAM_UNCOR_PARITY},
+ {UBFERR, CAM_UNEXP_BUSFREE},
+ {ABORTIO, CAM_REQ_ABORTED},
+ {-1, CAM_UNREC_HBA_ERROR}
+};
+
+#define SIM2SLP(sim) ((struct scsi_low_softc *) cam_sim_softc((sim)))
+
+/* XXX:
+ * Please check a polling hz, currently we assume scsi_low_poll() is
+ * called each 1 ms.
+ */
+#define SCSI_LOW_CAM_POLL_HZ 1000 /* OK ? */
+
+static void
+scsi_low_poll_cam(sim)
+ struct cam_sim *sim;
+{
+ struct scsi_low_softc *slp = SIM2SLP(sim);
+
+ (*slp->sl_funcs->scsi_low_poll) (slp);
+
+ if (slp->sl_si.si_poll_count ++ >=
+ SCSI_LOW_CAM_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
+ {
+ slp->sl_si.si_poll_count = 0;
+ scsi_low_timeout_check(slp);
+ }
+}
+
+static void
+scsi_low_cam_rescan_callback(periph, ccb)
+ struct cam_periph *periph;
+ union ccb *ccb;
+{
+
+ xpt_free_path(ccb->ccb_h.path);
+ free(ccb, M_DEVBUF);
+#if __FreeBSD_version < 400001
+ free(periph, M_DEVBUF);
+#endif
+}
+
+static void
+scsi_low_rescan_bus_cam(slp)
+ struct scsi_low_softc *slp;
+{
+ struct cam_path *path;
+ union ccb *ccb = malloc(sizeof(union ccb), M_DEVBUF, M_WAITOK);
+#if __FreeBSD_version < 400001
+ struct cam_periph *xpt_periph = malloc(sizeof(struct cam_periph),
+ M_DEVBUF, M_WAITOK);
+#endif
+ cam_status status;
+
+ bzero(ccb, sizeof(union ccb));
+
+ status = xpt_create_path(&path, xpt_periph,
+ cam_sim_path(slp->sl_si.sim), -1, 0);
+ if (status != CAM_REQ_CMP)
+ return;
+
+ xpt_setup_ccb(&ccb->ccb_h, path, 5);
+ ccb->ccb_h.func_code = XPT_SCAN_BUS;
+ ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback;
+ ccb->crcn.flags = CAM_FLAG_NONE;
+ xpt_action(ccb);
+}
+
+void
+scsi_low_scsi_action_cam(sim, ccb)
+ struct cam_sim *sim;
+ union ccb *ccb;
+{
+ struct scsi_low_softc *slp = SIM2SLP(sim);
+ struct targ_info *ti;
+ struct lun_info *li;
+ struct slccb *cb;
+ u_int lun, flags, msg, target;
+ int s, rv;
+
+ target = (u_int) (ccb->ccb_h.target_id);
+ lun = (u_int) ccb->ccb_h.target_lun;
+
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_ACTION, target) != 0)
+ {
+ printf("%s: cam_action: func code 0x%x target: %d, lun: %d\n",
+ slp->sl_xname, ccb->ccb_h.func_code, target, lun);
+ }
+#endif /* SCSI_LOW_DEBUG */
+
+ switch (ccb->ccb_h.func_code) {
+ case XPT_SCSI_IO: /* Execute the requested I/O operation */
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
+ {
+ printf("%s: invalid target/lun\n", slp->sl_xname);
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+
+ if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)) {
+ ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_done(ccb);
+ return;
+ }
+
+ ti = slp->sl_ti[target];
+ cb->osdep = ccb;
+ cb->bp = NULL;
+ if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
+ flags = CCB_AUTOSENSE | CCB_SCSIIO;
+ else
+ flags = CCB_SCSIIO;
+
+ s = SCSI_LOW_SPLSCSI();
+ li = scsi_low_alloc_li(ti, lun, 1);
+
+ if (ti->ti_setup_msg != 0)
+ {
+ scsi_low_message_enqueue(slp, ti, li, CCB_AUTOSENSE);
+ }
+
+ scsi_low_enqueue(slp, ti, li, cb, flags, 0);
+
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ABORT_CHECK, target) != 0)
+ {
+ scsi_low_test_abort(slp, ti, li);
+ }
+#endif /* SCSI_LOW_DEBUG */
+ splx(s);
+ break;
+
+ case XPT_EN_LUN: /* Enable LUN as a target */
+ case XPT_TARGET_IO: /* Execute target I/O request */
+ case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */
+ case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/
+ /* XXX Implement */
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+
+ case XPT_ABORT: /* Abort the specified CCB */
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if (target == CAM_TARGET_WILDCARD || lun == CAM_LUN_WILDCARD)
+ {
+ printf("%s: invalid target/lun\n", slp->sl_xname);
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+
+ s = SCSI_LOW_SPLSCSI();
+ cb = scsi_low_find_ccb(slp, target, lun, ccb->cab.abort_ccb);
+ rv = scsi_low_abort_ccb(slp, cb);
+ splx(s);
+
+ if (rv == 0)
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ else
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+
+ case XPT_SET_TRAN_SETTINGS: {
+ struct ccb_trans_settings *cts;
+ u_int val;
+
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if (target == CAM_TARGET_WILDCARD)
+ {
+ printf("%s: invalid target\n", slp->sl_xname);
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+ cts = &ccb->cts;
+ ti = slp->sl_ti[target];
+ if (lun == CAM_LUN_WILDCARD)
+ lun = 0;
+
+ s = SCSI_LOW_SPLSCSI();
+ if ((cts->valid & (CCB_TRANS_BUS_WIDTH_VALID |
+ CCB_TRANS_SYNC_RATE_VALID |
+ CCB_TRANS_SYNC_OFFSET_VALID)) != 0)
+ {
+ if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
+ val = cts->bus_width;
+ if (val < ti->ti_width)
+ ti->ti_width = val;
+ }
+ if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) {
+ val = cts->sync_period;
+ if (val == 0 || val > ti->ti_maxsynch.period)
+ ti->ti_maxsynch.period = val;
+ }
+ if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
+ val = cts->sync_offset;
+ if (val < ti->ti_maxsynch.offset)
+ ti->ti_maxsynch.offset = val;
+ }
+
+ ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
+ scsi_low_calcf_target(ti);
+ }
+
+ if ((cts->valid & (CCB_TRANS_DISC_VALID |
+ CCB_TRANS_TQ_VALID)) != 0)
+ {
+ li = scsi_low_alloc_li(ti, lun, 1);
+ if ((cts->valid & CCB_TRANS_DISC_VALID) != 0)
+ {
+ if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
+ li->li_quirks |= SCSI_LOW_DISK_DISC;
+ else
+ li->li_quirks &= ~SCSI_LOW_DISK_DISC;
+ }
+ if ((cts->valid & CCB_TRANS_TQ_VALID) != 0)
+ {
+ if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
+ li->li_quirks |= SCSI_LOW_DISK_QTAG;
+ else
+ li->li_quirks &= ~SCSI_LOW_DISK_QTAG;
+ }
+
+ li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
+ scsi_low_calcf_target(ti);
+ scsi_low_calcf_lun(li);
+ if ((slp->sl_show_result & SHOW_CALCF_RES) != 0)
+ scsi_low_calcf_show(li);
+ }
+ splx(s);
+
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+
+ case XPT_GET_TRAN_SETTINGS: {
+ struct ccb_trans_settings *cts;
+ u_int diskflags;
+
+ cts = &ccb->cts;
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if (target == CAM_TARGET_WILDCARD)
+ {
+ printf("%s: invalid target\n", slp->sl_xname);
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+ ti = slp->sl_ti[target];
+ if (lun == CAM_LUN_WILDCARD)
+ lun = 0;
+
+ s = SCSI_LOW_SPLSCSI();
+ li = scsi_low_alloc_li(ti, lun, 1);
+#ifdef CAM_NEW_TRAN_CODE
+ if (li != NULL && cts->type == CTS_TYPE_CURRENT_SETTINGS) {
+ struct ccb_trans_settings_scsi *scsi =
+ &cts->proto_specific.scsi;
+ struct ccb_trans_settings_spi *spi =
+ &cts->xport_specific.spi;
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID)
+ {
+ ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+ printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n",
+ slp->sl_xname);
+ goto settings_out;
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+ cts->protocol = PROTO_SCSI;
+ cts->protocol_version = SCSI_REV_2;
+ cts->transport = XPORT_SPI;
+ cts->transport_version = 2;
+
+ scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
+ spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
+
+ diskflags = li->li_diskflags & li->li_cfgflags;
+ if (diskflags & SCSI_LOW_DISK_DISC)
+ spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
+ if (diskflags & SCSI_LOW_DISK_QTAG)
+ scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
+
+ spi->sync_period = ti->ti_maxsynch.period;
+ spi->valid |= CTS_SPI_VALID_SYNC_RATE;
+ spi->sync_offset = ti->ti_maxsynch.offset;
+ spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
+
+ spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
+ spi->bus_width = ti->ti_width;
+
+ if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
+ scsi->valid = CTS_SCSI_VALID_TQ;
+ spi->valid |= CTS_SPI_VALID_DISC;
+ } else
+ scsi->valid = 0;
+ } else
+ ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+#else
+ if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0)
+ {
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if ((li->li_flags_valid & SCSI_LOW_LUN_FLAGS_DISK_VALID) == 0)
+ {
+ ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+ printf("%s: invalid GET_TRANS_USER_SETTINGS call\n",
+ slp->sl_xname);
+ goto settings_out;
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+ diskflags = li->li_diskflags & li->li_cfgflags;
+ if ((diskflags & SCSI_LOW_DISK_DISC) != 0)
+ cts->flags |= CCB_TRANS_DISC_ENB;
+ else
+ cts->flags &= ~CCB_TRANS_DISC_ENB;
+ if ((diskflags & SCSI_LOW_DISK_QTAG) != 0)
+ cts->flags |= CCB_TRANS_TAG_ENB;
+ else
+ cts->flags &= ~CCB_TRANS_TAG_ENB;
+ }
+ else if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
+ {
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if (li->li_flags_valid != SCSI_LOW_LUN_FLAGS_ALL_VALID)
+ {
+ ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+ printf("%s: invalid GET_TRANS_CURRENT_SETTINGS call\n",
+ slp->sl_xname);
+ goto settings_out;
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+ if ((li->li_flags & SCSI_LOW_DISC) != 0)
+ cts->flags |= CCB_TRANS_DISC_ENB;
+ else
+ cts->flags &= ~CCB_TRANS_DISC_ENB;
+ if ((li->li_flags & SCSI_LOW_QTAG) != 0)
+ cts->flags |= CCB_TRANS_TAG_ENB;
+ else
+ cts->flags &= ~CCB_TRANS_TAG_ENB;
+ }
+ else
+ {
+ ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+ goto settings_out;
+ }
+
+ cts->sync_period = ti->ti_maxsynch.period;
+ cts->sync_offset = ti->ti_maxsynch.offset;
+ cts->bus_width = ti->ti_width;
+
+ cts->valid = CCB_TRANS_SYNC_RATE_VALID
+ | CCB_TRANS_SYNC_OFFSET_VALID
+ | CCB_TRANS_BUS_WIDTH_VALID
+ | CCB_TRANS_DISC_VALID
+ | CCB_TRANS_TQ_VALID;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+#endif
+settings_out:
+ splx(s);
+ xpt_done(ccb);
+ break;
+ }
+
+ case XPT_CALC_GEOMETRY: { /* not yet HN2 */
+ struct ccb_calc_geometry *ccg;
+ u_int32_t size_mb;
+ u_int32_t secs_per_cylinder;
+ int extended;
+
+ extended = 1;
+ ccg = &ccb->ccg;
+ size_mb = ccg->volume_size
+ / ((1024L * 1024L) / ccg->block_size);
+
+ if (size_mb > 1024 && extended) {
+ ccg->heads = 255;
+ ccg->secs_per_track = 63;
+ } else {
+ ccg->heads = 64;
+ ccg->secs_per_track = 32;
+ }
+ secs_per_cylinder = ccg->heads * ccg->secs_per_track;
+ ccg->cylinders = ccg->volume_size / secs_per_cylinder;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+
+ case XPT_RESET_BUS: /* Reset the specified SCSI bus */
+ s = SCSI_LOW_SPLSCSI();
+ scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL);
+ splx(s);
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+
+ case XPT_TERM_IO: /* Terminate the I/O process */
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+
+ case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if (target == CAM_TARGET_WILDCARD)
+ {
+ printf("%s: invalid target\n", slp->sl_xname);
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+
+ msg = SCSI_LOW_MSG_RESET;
+ if (((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL))
+ {
+ ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_done(ccb);
+ return;
+ }
+
+ ti = slp->sl_ti[target];
+ if (lun == CAM_LUN_WILDCARD)
+ lun = 0;
+ cb->osdep = ccb;
+ cb->bp = NULL;
+ if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
+ flags = CCB_AUTOSENSE | CCB_NORETRY | CCB_URGENT;
+ else
+ flags = CCB_NORETRY | CCB_URGENT;
+
+ s = SCSI_LOW_SPLSCSI();
+ li = scsi_low_alloc_li(ti, lun, 1);
+ scsi_low_enqueue(slp, ti, li, cb, flags, msg);
+ splx(s);
+ break;
+
+ case XPT_PATH_INQ: { /* Path routing inquiry */
+ struct ccb_pathinq *cpi = &ccb->cpi;
+
+ cpi->version_num = scsi_low_version_major;
+ cpi->hba_inquiry = PI_TAG_ABLE | PI_LINKED_CDB;
+ ti = slp->sl_ti[slp->sl_hostid]; /* host id */
+ if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
+ cpi->hba_inquiry |= PI_WIDE_16;
+ if (ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
+ cpi->hba_inquiry |= PI_WIDE_32;
+ if (ti->ti_maxsynch.offset > 0)
+ cpi->hba_inquiry |= PI_SDTR_ABLE;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = 0;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = slp->sl_ntargs - 1;
+ cpi->max_lun = slp->sl_nluns - 1;
+ cpi->initiator_id = slp->sl_hostid;
+ cpi->bus_id = cam_sim_bus(sim);
+ cpi->base_transfer_speed = 3300;
+#ifdef CAM_NEW_TRAN_CODE
+ cpi->transport = XPORT_SPI;
+ cpi->transport_version = 2;
+ cpi->protocol = PROTO_SCSI;
+ cpi->protocol_version = SCSI_REV_2;
+#endif
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+
+ default:
+ printf("scsi_low: non support func_code = %d ",
+ ccb->ccb_h.func_code);
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ }
+}
+
+static int
+scsi_low_attach_cam(slp)
+ struct scsi_low_softc *slp;
+{
+ struct cam_devq *devq;
+ int tagged_openings;
+
+ sprintf(slp->sl_xname, "%s%d",
+ DEVPORT_DEVNAME(slp->sl_dev), DEVPORT_DEVUNIT(slp->sl_dev));
+
+ devq = cam_simq_alloc(SCSI_LOW_NCCB);
+ if (devq == NULL)
+ return (ENOMEM);
+
+ /*
+ * ask the adapter what subunits are present
+ */
+ tagged_openings = min(slp->sl_openings, SCSI_LOW_MAXNEXUS);
+ slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam,
+ scsi_low_poll_cam,
+ DEVPORT_DEVNAME(slp->sl_dev), slp,
+ DEVPORT_DEVUNIT(slp->sl_dev),
+ slp->sl_openings, tagged_openings, devq);
+
+ if (slp->sl_si.sim == NULL) {
+ cam_simq_free(devq);
+ return ENODEV;
+ }
+
+ if (xpt_bus_register(slp->sl_si.sim, 0) != CAM_SUCCESS) {
+ free(slp->sl_si.sim, M_DEVBUF);
+ return ENODEV;
+ }
+
+ if (xpt_create_path(&slp->sl_si.path, /*periph*/NULL,
+ cam_sim_path(slp->sl_si.sim), CAM_TARGET_WILDCARD,
+ CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+ xpt_bus_deregister(cam_sim_path(slp->sl_si.sim));
+ cam_sim_free(slp->sl_si.sim, /*free_simq*/TRUE);
+ free(slp->sl_si.sim, M_DEVBUF);
+ return ENODEV;
+ }
+
+ slp->sl_show_result = SHOW_CALCF_RES; /* OK ? */
+ return 0;
+}
+
+static int
+scsi_low_world_start_cam(slp)
+ struct scsi_low_softc *slp;
+{
+
+ if (!cold)
+ scsi_low_rescan_bus_cam(slp);
+ return 0;
+}
+
+static int
+scsi_low_dettach_cam(slp)
+ struct scsi_low_softc *slp;
+{
+
+ xpt_async(AC_LOST_DEVICE, slp->sl_si.path, NULL);
+ xpt_free_path(slp->sl_si.path);
+ xpt_bus_deregister(cam_sim_path(slp->sl_si.sim));
+ cam_sim_free(slp->sl_si.sim, /* free_devq */ TRUE);
+ return 0;
+}
+
+static int
+scsi_low_ccb_setup_cam(slp, cb)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+{
+ union ccb *ccb = (union ccb *) cb->osdep;
+
+ if ((cb->ccb_flags & CCB_SCSIIO) != 0)
+ {
+ cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes;
+ cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len;
+ cb->ccb_scp.scp_data = ccb->csio.data_ptr;
+ cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len;
+ if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
+ cb->ccb_scp.scp_direction = SCSI_LOW_WRITE;
+ else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */
+ cb->ccb_scp.scp_direction = SCSI_LOW_READ;
+ cb->ccb_tcmax = ccb->ccb_h.timeout / 1000;
+ }
+ else
+ {
+ scsi_low_unit_ready_cmd(cb);
+ }
+ return SCSI_LOW_START_QTAG;
+}
+
+static int
+scsi_low_done_cam(slp, cb)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+{
+ union ccb *ccb;
+
+ ccb = (union ccb *) cb->osdep;
+ if (cb->ccb_error == 0)
+ {
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ ccb->csio.resid = 0;
+ }
+ else
+ {
+ if (cb->ccb_rcnt >= slp->sl_max_retry)
+ cb->ccb_error |= ABORTIO;
+
+ if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
+ (cb->ccb_error & ABORTIO) == 0)
+ return EJUSTRETURN;
+
+ if ((cb->ccb_error & SENSEIO) != 0)
+ {
+ memcpy(&ccb->csio.sense_data,
+ &cb->ccb_sense,
+ sizeof(ccb->csio.sense_data));
+ }
+
+ ccb->ccb_h.status = scsi_low_translate_error_code(cb,
+ &scsi_low_error_code_cam[0]);
+
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if ((cb->ccb_flags & CCB_SILENT) == 0 &&
+ cb->ccb_scp.scp_cmdlen > 0 &&
+ (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
+ SCSI_LOW_CMD_ABORT_WARNING) != 0)
+ {
+ printf("%s: WARNING: scsi_low IO abort\n",
+ slp->sl_xname);
+ scsi_low_print(slp, NULL);
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+ }
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0)
+ ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
+
+ if (cb->ccb_scp.scp_status == ST_UNKNOWN)
+ ccb->csio.scsi_status = 0; /* XXX */
+ else
+ ccb->csio.scsi_status = cb->ccb_scp.scp_status;
+
+ if ((cb->ccb_flags & CCB_NOSDONE) == 0)
+ xpt_done(ccb);
+ return 0;
+}
+
+static void
+scsi_low_timeout_cam(slp, ch, action)
+ struct scsi_low_softc *slp;
+ int ch;
+ int action;
+{
+
+ switch (ch)
+ {
+ case SCSI_LOW_TIMEOUT_CH_IO:
+ switch (action)
+ {
+ case SCSI_LOW_TIMEOUT_START:
+ slp->sl_si.timeout_ch = timeout(scsi_low_timeout, slp,
+ hz / SCSI_LOW_TIMEOUT_HZ);
+ break;
+ case SCSI_LOW_TIMEOUT_STOP:
+ untimeout(scsi_low_timeout, slp, slp->sl_si.timeout_ch);
+ break;
+ }
+ break;
+
+ case SCSI_LOW_TIMEOUT_CH_ENGAGE:
+ switch (action)
+ {
+ case SCSI_LOW_TIMEOUT_START:
+ slp->sl_si.engage_ch = timeout(scsi_low_engage, slp, 1);
+ break;
+ case SCSI_LOW_TIMEOUT_STOP:
+ untimeout(scsi_low_engage, slp, slp->sl_si.engage_ch);
+ break;
+ }
+ break;
+ case SCSI_LOW_TIMEOUT_CH_RECOVER:
+ break;
+ }
+}
+
+#endif /* SCSI_LOW_INTERFACE_CAM */
+
+/*=============================================================
+ * END OF OS switch (All OS depend fucntions should be above)
+ =============================================================*/
+
+/**************************************************************
+ * scsi low deactivate and activate
+ **************************************************************/
+int
+scsi_low_is_busy(slp)
+ struct scsi_low_softc *slp;
+{
+
+ if (slp->sl_nio > 0)
+ return EBUSY;
+ return 0;
+}
+
+int
+scsi_low_deactivate(slp)
+ struct scsi_low_softc *slp;
+{
+ int s;
+
+ s = SCSI_LOW_SPLSCSI();
+ slp->sl_flags |= HW_INACTIVE;
+ (*slp->sl_osdep_fp->scsi_low_osdep_timeout)
+ (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_STOP);
+ (*slp->sl_osdep_fp->scsi_low_osdep_timeout)
+ (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP);
+ splx(s);
+ return 0;
+}
+
+int
+scsi_low_activate(slp)
+ struct scsi_low_softc *slp;
+{
+ int error, s;
+
+ s = SCSI_LOW_SPLSCSI();
+ slp->sl_flags &= ~HW_INACTIVE;
+ if ((error = scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, NULL)) != 0)
+ {
+ slp->sl_flags |= HW_INACTIVE;
+ splx(s);
+ return error;
+ }
+
+ slp->sl_timeout_count = 0;
+ (*slp->sl_osdep_fp->scsi_low_osdep_timeout)
+ (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
+ splx(s);
+ return 0;
+}
+
+/**************************************************************
+ * scsi low log
+ **************************************************************/
+#ifdef SCSI_LOW_DIAGNOSTIC
+static void scsi_low_msg_log_init __P((struct scsi_low_msg_log *));
+static void scsi_low_msg_log_write __P((struct scsi_low_msg_log *, u_int8_t *,
+int));
+static void scsi_low_msg_log_show __P((struct scsi_low_msg_log *, char *, int));
+
+static void
+scsi_low_msg_log_init(slmlp)
+ struct scsi_low_msg_log *slmlp;
+{
+
+ slmlp->slml_ptr = 0;
+}
+
+static void
+scsi_low_msg_log_write(slmlp, datap, len)
+ struct scsi_low_msg_log *slmlp;
+ u_int8_t *datap;
+ int len;
+{
+ int ptr, ind;
+
+ if (slmlp->slml_ptr >= SCSI_LOW_MSG_LOG_DATALEN)
+ return;
+
+ ptr = slmlp->slml_ptr ++;
+ for (ind = 0; ind < sizeof(slmlp->slml_msg[0]) && ind < len; ind ++)
+ slmlp->slml_msg[ptr].msg[ind] = datap[ind];
+ for ( ; ind < sizeof(slmlp->slml_msg[0]); ind ++)
+ slmlp->slml_msg[ptr].msg[ind] = 0;
+}
+
+static void
+scsi_low_msg_log_show(slmlp, s, len)
+ struct scsi_low_msg_log *slmlp;
+ char *s;
+ int len;
+{
+ int ptr, ind;
+
+ printf("%s: (%d) ", s, slmlp->slml_ptr);
+ for (ptr = 0; ptr < slmlp->slml_ptr; ptr ++)
+ {
+ for (ind = 0; ind < len && ind < sizeof(slmlp->slml_msg[0]);
+ ind ++)
+ {
+ printf("[%x]", (u_int) slmlp->slml_msg[ptr].msg[ind]);
+ }
+ printf(">");
+ }
+ printf("\n");
+}
+#endif /* SCSI_LOW_DIAGNOSTIC */
+
/**************************************************************
* power control
**************************************************************/
@@ -167,17 +1723,15 @@ scsi_low_engage(arg)
void *arg;
{
struct scsi_low_softc *slp = arg;
- int s = splbio();
+ int s = SCSI_LOW_SPLSCSI();
switch (slp->sl_rstep)
{
case 0:
slp->sl_rstep ++;
(*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
-#ifdef __FreeBSD__
- slp->engage_ch =
-#endif
- timeout(scsi_low_engage, slp, 1);
+ (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp,
+ SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_START);
break;
case 1:
@@ -197,14 +1751,15 @@ scsi_low_init(slp, flags)
struct scsi_low_softc *slp;
u_int flags;
{
+ int rv = 0;
+
+ slp->sl_flags |= HW_INITIALIZING;
+ /* clear power control timeout */
if ((slp->sl_flags & HW_POWERCTRL) != 0)
{
-#ifdef __FreeBSD__
- untimeout(scsi_low_engage, slp, slp->engage_ch);
-#else /* NetBSD */
- untimeout(scsi_low_engage, slp);
-#endif
+ (*slp->sl_osdep_fp->scsi_low_osdep_timeout) (slp,
+ SCSI_LOW_TIMEOUT_CH_ENGAGE, SCSI_LOW_TIMEOUT_STOP);
slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME);
slp->sl_active = 1;
slp->sl_powc = SCSI_LOW_POWDOWN_TC;
@@ -213,12 +1768,19 @@ scsi_low_init(slp, flags)
/* reset current nexus */
scsi_low_reset_nexus(slp, flags);
if ((slp->sl_flags & HW_INACTIVE) != 0)
- return EBUSY;
+ {
+ rv = EBUSY;
+ goto out;
+ }
- if (flags == SCSI_LOW_RESTART_SOFT)
- return 0;
+ if (flags != SCSI_LOW_RESTART_SOFT)
+ {
+ rv = ((*slp->sl_funcs->scsi_low_init) (slp, flags));
+ }
- return ((*slp->sl_funcs->scsi_low_init) (slp, flags));
+out:
+ slp->sl_flags &= ~HW_INITIALIZING;
+ return rv;
}
/**************************************************************
@@ -230,6 +1792,7 @@ scsi_low_alloc_li(ti, lun, alloc)
int lun;
int alloc;
{
+ struct scsi_low_softc *slp = ti->ti_sc;
struct lun_info *li;
li = LIST_FIRST(&ti->ti_litab);
@@ -252,20 +1815,32 @@ scsi_low_alloc_li(ti, lun, alloc)
if (alloc == 0)
return li;
- li = malloc(sizeof(struct lun_info), M_DEVBUF, M_NOWAIT);
+ li = SCSI_LOW_MALLOC(ti->ti_lunsize);
if (li == NULL)
panic("no lun info mem\n");
- memset(li, 0, sizeof(struct lun_info));
+ SCSI_LOW_BZERO(li, ti->ti_lunsize);
li->li_lun = lun;
li->li_ti = ti;
-#if defined(SDEV_NOPARITY) && defined(SDEV_NODISC)
- li->li_quirks = SDEV_NOPARITY | SDEV_NODISC;
-#endif /* SDEV_NOPARITY && SDEV_NODISC */
- li->li_cfgflags = 0xffff0000 | SCSI_LOW_SYNC;
+ li->li_cfgflags = SCSI_LOW_SYNC | SCSI_LOW_LINK | SCSI_LOW_DISC |
+ SCSI_LOW_QTAG;
+ li->li_quirks = li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
+ li->li_flags_valid = SCSI_LOW_LUN_FLAGS_USER_VALID;
+#ifdef SCSI_LOW_FLAGS_QUIRKS_OK
+ li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_QUIRKS_VALID;
+#endif /* SCSI_LOW_FLAGS_QUIRKS_OK */
+
+ li->li_qtagbits = (u_int) -1;
+
+ TAILQ_INIT(&li->li_discq);
LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain);
+ /* host specific structure initialization per lun */
+ if (slp->sl_funcs->scsi_low_lun_init != NULL)
+ (*slp->sl_funcs->scsi_low_lun_init)
+ (slp, ti, li, SCSI_LOW_INFO_ALLOC);
+ scsi_low_calcf_lun(li);
return li;
}
@@ -273,31 +1848,40 @@ scsi_low_alloc_li(ti, lun, alloc)
* allocate targ_info
**************************************************************/
static struct targ_info *
-scsi_low_alloc_ti(slp, targ, targ_size)
+scsi_low_alloc_ti(slp, targ)
struct scsi_low_softc *slp;
- int targ, targ_size;
+ int targ;
{
struct targ_info *ti;
if (TAILQ_FIRST(&slp->sl_titab) == NULL)
TAILQ_INIT(&slp->sl_titab);
- ti = malloc(targ_size, M_DEVBUF, M_NOWAIT);
+ ti = SCSI_LOW_MALLOC(slp->sl_targsize);
if (ti == NULL)
panic("%s short of memory\n", slp->sl_xname);
- memset(ti, 0, targ_size);
+ SCSI_LOW_BZERO(ti, slp->sl_targsize);
ti->ti_id = targ;
ti->ti_sc = slp;
slp->sl_ti[targ] = ti;
TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain);
- TAILQ_INIT(&ti->ti_discq);
LIST_INIT(&ti->ti_litab);
- /* host specific structure initialization per target */
- (void) ((*slp->sl_funcs->scsi_low_targ_init) (slp, ti));
+ ti->ti_quirks = ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
+ ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
+ ti->ti_flags_valid = SCSI_LOW_TARG_FLAGS_USER_VALID;
+#ifdef SCSI_LOW_FLAGS_QUIRKS_OK
+ ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_QUIRKS_VALID;
+#endif /* SCSI_LOW_FLAGS_QUIRKS_OK */
+ if (slp->sl_funcs->scsi_low_targ_init != NULL)
+ {
+ (*slp->sl_funcs->scsi_low_targ_init)
+ (slp, ti, SCSI_LOW_INFO_ALLOC);
+ }
+ scsi_low_calcf_target(ti);
return ti;
}
@@ -310,13 +1894,24 @@ scsi_low_free_ti(slp)
for (ti = TAILQ_FIRST(&slp->sl_titab); ti; ti = tib)
{
- tib = TAILQ_NEXT(ti, ti_chain);
for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli)
{
+ if (slp->sl_funcs->scsi_low_lun_init != NULL)
+ {
+ (*slp->sl_funcs->scsi_low_lun_init)
+ (slp, ti, li, SCSI_LOW_INFO_DEALLOC);
+ }
nli = LIST_NEXT(li, lun_chain);
- free(li, M_DEVBUF);
+ SCSI_LOW_FREE(li);
}
- free(ti, M_DEVBUF);
+
+ if (slp->sl_funcs->scsi_low_targ_init != NULL)
+ {
+ (*slp->sl_funcs->scsi_low_targ_init)
+ (slp, ti, SCSI_LOW_INFO_DEALLOC);
+ }
+ tib = TAILQ_NEXT(ti, ti_chain);
+ SCSI_LOW_FREE(ti);
}
}
@@ -324,577 +1919,521 @@ scsi_low_free_ti(slp)
* timeout
**************************************************************/
void
+scsi_low_bus_idle(slp)
+ struct scsi_low_softc *slp;
+{
+
+ slp->sl_retry_sel = 0;
+ if (slp->sl_Tnexus == NULL)
+ scsi_low_start(slp);
+}
+
+static void
scsi_low_timeout(arg)
void *arg;
{
struct scsi_low_softc *slp = arg;
+ int s;
+
+ s = SCSI_LOW_SPLSCSI();
+ (void) scsi_low_timeout_check(slp);
+ (*slp->sl_osdep_fp->scsi_low_osdep_timeout)
+ (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
+ splx(s);
+}
+
+static int
+scsi_low_timeout_check(slp)
+ struct scsi_low_softc *slp;
+{
struct targ_info *ti;
+ struct lun_info *li;
struct slccb *cb = NULL; /* XXX */
- int s = splbio();
- /* check */
- if ((ti = slp->sl_nexus) != NULL && (cb = ti->ti_nexus) != NULL)
+ /* selection restart */
+ if (slp->sl_retry_sel != 0)
{
- cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
- if (cb->ccb_tc < 0)
- goto bus_reset;
- }
- else if (slp->sl_disc > 0)
- {
- struct targ_info *ti;
+ slp->sl_retry_sel = 0;
+ if (slp->sl_Tnexus != NULL)
+ goto step1;
- TAILQ_FOREACH(ti, &slp->sl_titab, ti_chain)
+ cb = TAILQ_FIRST(&slp->sl_start);
+ if (cb == NULL)
+ goto step1;
+
+ if (cb->ccb_selrcnt >= SCSI_LOW_MAX_SELECTION_RETRY)
{
- TAILQ_FOREACH(cb, &ti->ti_discq, ccb_chain)
- {
- cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
- if (cb->ccb_tc < 0)
- goto bus_reset;
- }
+ cb->ccb_flags |= CCB_NORETRY;
+ cb->ccb_error |= SELTIMEOUTIO;
+ if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
+ panic("%s: ccb not finished\n", slp->sl_xname);
}
+
+ if (slp->sl_Tnexus == NULL)
+ scsi_low_start(slp);
}
- else
+
+ /* call hardware timeout */
+step1:
+ if (slp->sl_funcs->scsi_low_timeout != NULL)
{
- cb = TAILQ_FIRST(&slp->sl_start);
- if (cb != NULL)
+ (*slp->sl_funcs->scsi_low_timeout) (slp);
+ }
+
+ if (slp->sl_timeout_count ++ <
+ SCSI_LOW_TIMEOUT_CHECK_INTERVAL * SCSI_LOW_TIMEOUT_HZ)
+ return 0;
+
+ slp->sl_timeout_count = 0;
+ if (slp->sl_nio > 0)
+ {
+ if ((cb = slp->sl_Qnexus) != NULL)
{
cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
if (cb->ccb_tc < 0)
goto bus_reset;
}
- else if ((slp->sl_flags & HW_POWERCTRL) != 0)
+ else if (slp->sl_disc == 0)
{
- if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0)
- goto out;
+ if ((cb = TAILQ_FIRST(&slp->sl_start)) == NULL)
+ return 0;
- if (slp->sl_active != 0)
- {
- slp->sl_powc = SCSI_LOW_POWDOWN_TC;
- slp->sl_active = 0;
- goto out;
- }
+ cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
+ if (cb->ccb_tc < 0)
+ goto bus_reset;
+ }
+ else for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
+ ti = TAILQ_NEXT(ti, ti_chain))
+ {
+ if (ti->ti_disc == 0)
+ continue;
- slp->sl_powc --;
- if (slp->sl_powc < 0)
+ for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
+ li = LIST_NEXT(li, lun_chain))
{
- slp->sl_powc = SCSI_LOW_POWDOWN_TC;
- slp->sl_flags |= HW_POWDOWN;
- (*slp->sl_funcs->scsi_low_power)
- (slp, SCSI_LOW_POWDOWN);
+ for (cb = TAILQ_FIRST(&li->li_discq);
+ cb != NULL;
+ cb = TAILQ_NEXT(cb, ccb_chain))
+ {
+ cb->ccb_tc -=
+ SCSI_LOW_TIMEOUT_CHECK_INTERVAL;
+ if (cb->ccb_tc < 0)
+ goto bus_reset;
+ }
}
}
+
}
+ else if ((slp->sl_flags & HW_POWERCTRL) != 0)
+ {
+ if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0)
+ return 0;
-out:
-#ifdef __FreeBSD__
- slp->timeout_ch =
-#endif
- timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz);
+ if (slp->sl_active != 0)
+ {
+ slp->sl_powc = SCSI_LOW_POWDOWN_TC;
+ slp->sl_active = 0;
+ return 0;
+ }
- splx(s);
- return;
+ slp->sl_powc --;
+ if (slp->sl_powc < 0)
+ {
+ slp->sl_powc = SCSI_LOW_POWDOWN_TC;
+ slp->sl_flags |= HW_POWDOWN;
+ (*slp->sl_funcs->scsi_low_power)
+ (slp, SCSI_LOW_POWDOWN);
+ }
+ }
+ return 0;
bus_reset:
cb->ccb_error |= TIMEOUTIO;
+ printf("%s: slccb (0x%lx) timeout!\n", slp->sl_xname, (u_long) cb);
scsi_low_info(slp, NULL, "scsi bus hangup. try to recover.");
scsi_low_init(slp, SCSI_LOW_RESTART_HARD);
scsi_low_start(slp);
-#ifdef __FreeBSD__
- slp->timeout_ch =
-#endif
- timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz);
-
- splx(s);
+ return ERESTART;
}
-/**************************************************************
- * CCB
- **************************************************************/
-GENERIC_CCB_STATIC_ALLOC(scsi_low, slccb)
-GENERIC_CCB(scsi_low, slccb, ccb_chain)
-/**************************************************************
- * SCSI INTERFACE (XS)
- **************************************************************/
-#define SCSI_LOW_MINPHYS 0x10000
+static int
+scsi_low_abort_ccb(slp, cb)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+{
+ struct targ_info *ti;
+ struct lun_info *li;
+ u_int msg;
-#ifdef __NetBSD__
-struct scsipi_device scsi_low_dev = {
- NULL, /* Use default error handler */
- NULL, /* have a queue, served by this */
- NULL, /* have no async handler */
- NULL, /* Use default 'done' routine */
-};
-#endif
+ if (cb == NULL)
+ return EINVAL;
+ if ((cb->ccb_omsgoutflag &
+ (SCSI_LOW_MSG_ABORT | SCSI_LOW_MSG_ABORT_QTAG)) != 0)
+ return EBUSY;
-#ifdef CAM
-static void
-scsi_low_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb)
-{
- xpt_free_path(ccb->ccb_h.path);
- free(ccb, M_DEVBUF);
-#if defined(__FreeBSD__) && __FreeBSD_version < 400001
- free(periph, M_DEVBUF);
-#endif
-}
+ ti = cb->ti;
+ li = cb->li;
+ if (cb->ccb_tag == SCSI_LOW_UNKTAG)
+ msg = SCSI_LOW_MSG_ABORT;
+ else
+ msg = SCSI_LOW_MSG_ABORT_QTAG;
-static void
-scsi_low_rescan_bus(struct scsi_low_softc *slp)
-{
- struct cam_path *path;
- union ccb *ccb = malloc(sizeof(union ccb), M_DEVBUF, M_WAITOK);
-#if defined(__FreeBSD__) && __FreeBSD_version < 400001
- struct cam_periph *xpt_periph = malloc(sizeof(struct cam_periph),
- M_DEVBUF, M_WAITOK);
-#endif
- cam_status status;
+ cb->ccb_error |= ABORTIO;
+ cb->ccb_flags |= CCB_NORETRY;
+ scsi_low_ccb_message_assert(cb, msg);
- bzero(ccb, sizeof(union ccb));
+ if (cb == slp->sl_Qnexus)
+ {
+ scsi_low_assert_msg(slp, ti, msg, 1);
+ }
+ else if ((cb->ccb_flags & CCB_DISCQ) != 0)
+ {
+ if (scsi_low_revoke_ccb(slp, cb, 0) == NULL)
+ panic("%s: revoked ccb done\n", slp->sl_xname);
- status = xpt_create_path(&path, xpt_periph,
- cam_sim_path(slp->sim), -1, 0);
- if (status != CAM_REQ_CMP)
- return;
+ cb->ccb_flags |= CCB_STARTQ;
+ TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
- xpt_setup_ccb(&ccb->ccb_h, path, 5);
- ccb->ccb_h.func_code = XPT_SCAN_BUS;
- ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback;
- ccb->crcn.flags = CAM_FLAG_NONE;
- xpt_action(ccb);
+ if (slp->sl_Tnexus == NULL)
+ scsi_low_start(slp);
+ }
+ else
+ {
+ if (scsi_low_revoke_ccb(slp, cb, 1) != NULL)
+ panic("%s: revoked ccb retried\n", slp->sl_xname);
+ }
+ return 0;
}
-#endif
+/**************************************************************
+ * Generic SCSI INTERFACE
+ **************************************************************/
int
-scsi_low_attach(slp, openings, ntargs, nluns, targ_size)
+scsi_low_attach(slp, openings, ntargs, nluns, targsize, lunsize)
struct scsi_low_softc *slp;
- int openings, ntargs, nluns, targ_size;
+ int openings, ntargs, nluns, targsize, lunsize;
{
struct targ_info *ti;
struct lun_info *li;
-#ifdef CAM
- struct cam_devq *devq;
-#else
- struct scsipi_adapter *sap;
-#endif
- int i, nccb;
+ int s, i, nccb, rv;
+
+#ifdef SCSI_LOW_INTERFACE_XS
+ slp->sl_osdep_fp = &scsi_low_osdep_funcs_xs;
+#endif /* SCSI_LOW_INTERFACE_XS */
+#ifdef SCSI_LOW_INTERFACE_CAM
+ slp->sl_osdep_fp = &scsi_low_osdep_funcs_cam;
+#endif /* SCSI_LOW_INTERFACE_CAM */
+
+ if (slp->sl_osdep_fp == NULL)
+ panic("scsi_low: interface not spcified\n");
-#ifdef CAM
- OS_DEPEND(sprintf(slp->sl_xname, "%s%d",
- DEVPORT_DEVNAME(slp->sl_dev), DEVPORT_DEVUNIT(slp->sl_dev)));
-#else
- OS_DEPEND(strncpy(slp->sl_xname, DEVPORT_DEVNAME(slp->sl_dev), 16));
-#endif
if (ntargs > SCSI_LOW_NTARGETS)
{
printf("scsi_low: %d targets are too large\n", ntargs);
printf("change kernel options SCSI_LOW_NTARGETS");
+ return EINVAL;
}
- if (targ_size < sizeof(struct targ_info))
- targ_size = sizeof(struct targ_info);
+ if (openings <= 0)
+ slp->sl_openings = (SCSI_LOW_NCCB / ntargs);
+ else
+ slp->sl_openings = openings;
+ slp->sl_ntargs = ntargs;
+ slp->sl_nluns = nluns;
+ slp->sl_max_retry = SCSI_LOW_MAX_RETRY;
+ if (lunsize < sizeof(struct lun_info))
+ lunsize = sizeof(struct lun_info);
+
+ if (targsize < sizeof(struct targ_info))
+ targsize = sizeof(struct targ_info);
+
+ slp->sl_targsize = targsize;
for (i = 0; i < ntargs; i ++)
{
- ti = scsi_low_alloc_ti(slp, i, targ_size);
+ ti = scsi_low_alloc_ti(slp, i);
+ ti->ti_lunsize = lunsize;
li = scsi_low_alloc_li(ti, 0, 1);
}
-#ifndef CAM
- sap = malloc(sizeof(*sap), M_DEVBUF, M_NOWAIT);
- if (sap == NULL)
- return ENOMEM;
-
- memset(sap, 0, sizeof(*sap));
- sap->scsipi_cmd = scsi_low_scsi_cmd;
- sap->scsipi_minphys = scsi_low_scsi_minphys;
-#ifdef SCSI_LOW_TARGET_OPEN
- sap->open_target_lu = scsi_low_target_open;
-#endif /* SCSI_LOW_TARGET_OPEN */
-#endif
-
- if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0)
- return EINVAL;
-
/* initialize queue */
- nccb = openings * (ntargs - 1);
+ nccb = openings * ntargs;
if (nccb >= SCSI_LOW_NCCB || nccb <= 0)
nccb = SCSI_LOW_NCCB;
scsi_low_init_ccbque(nccb);
TAILQ_INIT(&slp->sl_start);
- slp->sl_openings = openings;
- slp->sl_ntargs = ntargs;
- slp->sl_nluns = nluns;
+ /* call os depend attach */
+ s = SCSI_LOW_SPLSCSI();
+ rv = (*slp->sl_osdep_fp->scsi_low_osdep_attach) (slp);
+ if (rv != 0)
+ {
+ splx(s);
+ printf("%s: scsi_low_attach: osdep attach failed\n",
+ slp->sl_xname);
+ return EINVAL;
+ }
-#ifdef CAM
- /*
- * Prepare the scsibus_data area for the upperlevel
- * scsi code.
- */
- devq = cam_simq_alloc(256/*MAX_START*/);
- if (devq == NULL)
- return (0);
- /* scbus->adapter_link = &slp->sc_link; */
- /*
- * ask the adapter what subunits are present
- */
-
- slp->sim = cam_sim_alloc(scsi_low_scsi_action, scsi_low_poll,
- DEVPORT_DEVNAME(slp->sl_dev), slp,
- DEVPORT_DEVUNIT(slp->sl_dev), 1, 32/*MAX_TAGS*/, devq);
- if (slp->sim == NULL) {
- cam_simq_free(devq);
- return 0;
- }
-
- if (xpt_bus_register(slp->sim, 0) != CAM_SUCCESS) {
- free(slp->sim, M_DEVBUF);
- return 0;
- }
-
- if (xpt_create_path(&slp->path, /*periph*/NULL,
- cam_sim_path(slp->sim), CAM_TARGET_WILDCARD,
- CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
- xpt_bus_deregister(cam_sim_path(slp->sim));
- cam_sim_free(slp->sim, /*free_simq*/TRUE);
- free(slp->sim, M_DEVBUF);
- return 0;
- }
-#else /* !CAM */
- slp->sl_link.adapter_softc = slp;
- slp->sl_link.scsipi_scsi.adapter_target = slp->sl_hostid;
- slp->sl_link.scsipi_scsi.max_target = ntargs - 1;
- slp->sl_link.scsipi_scsi.max_lun = nluns - 1;
- slp->sl_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
- slp->sl_link.openings = openings;
- slp->sl_link.type = BUS_SCSI;
- slp->sl_link.adapter_softc = slp;
- slp->sl_link.adapter = sap;
- slp->sl_link.device = &scsi_low_dev;
-#endif
+ /* check hardware */
+ SCSI_LOW_DELAY(1000); /* wait for 1ms */
+ if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0)
+ {
+ splx(s);
+ printf("%s: scsi_low_attach: initialization failed\n",
+ slp->sl_xname);
+ return EINVAL;
+ }
/* start watch dog */
- slp->sl_max_retry = SCSI_LOW_MAX_RETRY;
-#ifdef __FreeBSD__
- slp->timeout_ch =
-#endif
- timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz);
-#ifdef CAM
- if (!cold)
- scsi_low_rescan_bus(slp);
-#endif
+ slp->sl_timeout_count = 0;
+ (*slp->sl_osdep_fp->scsi_low_osdep_timeout)
+ (slp, SCSI_LOW_TIMEOUT_CH_IO, SCSI_LOW_TIMEOUT_START);
+ LIST_INSERT_HEAD(&sl_tab, slp, sl_chain);
- return 0;
-}
+ /* fake call */
+ scsi_low_abort_ccb(slp, scsi_low_find_ccb(slp, 0, 0, NULL));
-#ifndef CAM
-static void
-scsi_low_scsi_minphys(bp)
- struct buf *bp;
-{
+#ifdef SCSI_LOW_START_UP_CHECK
+ /* probing devices */
+ scsi_low_start_up(slp);
+#endif /* SCSI_LOW_START_UP_CHECK */
- if (bp->b_bcount > SCSI_LOW_MINPHYS)
- bp->b_bcount = SCSI_LOW_MINPHYS;
- minphys(bp);
+ /* call os depend attach done*/
+ (*slp->sl_osdep_fp->scsi_low_osdep_world_start) (slp);
+ splx(s);
+ return 0;
}
-#endif
int
scsi_low_dettach(slp)
struct scsi_low_softc *slp;
{
+ int s, rv;
- if (slp->sl_disc > 0 || TAILQ_FIRST(&slp->sl_start) != NULL)
+ s = SCSI_LOW_SPLSCSI();
+ if (scsi_low_is_busy(slp) != 0)
+ {
+ splx(s);
return EBUSY;
+ }
- /*
- * scsipi does not have dettach bus fucntion.
- *
- scsipi_dettach_scsibus(&slp->sl_link);
- */
+ scsi_low_deactivate(slp);
-#ifdef CAM
- xpt_async(AC_LOST_DEVICE, slp->path, NULL);
- xpt_free_path(slp->path);
- xpt_bus_deregister(cam_sim_path(slp->sim));
- cam_sim_free(slp->sim, /* free_devq */ TRUE);
-#endif
+ rv = (*slp->sl_osdep_fp->scsi_low_osdep_dettach) (slp);
+ if (rv != 0)
+ {
+ splx(s);
+ return EBUSY;
+ }
scsi_low_free_ti(slp);
+ LIST_REMOVE(slp, sl_chain);
+ splx(s);
return 0;
}
-#ifdef CAM
-static void
-scsi_low_poll(struct cam_sim *sim)
-{
- struct scsi_low_softc *slp = (struct scsi_low_softc *) cam_sim_softc(sim);
- (*slp->sl_funcs->scsi_low_poll) (slp);
-}
-
-void
-scsi_low_scsi_action(struct cam_sim *sim, union ccb *ccb)
-{
- struct scsi_low_softc *slp = (struct scsi_low_softc *) cam_sim_softc(sim);
- int s, target = (u_int) (ccb->ccb_h.target_id);
+/**************************************************************
+ * Generic enqueue
+ **************************************************************/
+static int
+scsi_low_enqueue(slp, ti, li, cb, flags, msg)
+ struct scsi_low_softc *slp;
struct targ_info *ti;
struct lun_info *li;
struct slccb *cb;
+ u_int flags, msg;
+{
-#if 0
- printf("scsi_low_scsi_action() func code 0x%x Target: %d, LUN: %d\n",
- ccb->ccb_h.func_code, target, ccb->ccb_h.target_lun);
-#endif
- switch (ccb->ccb_h.func_code) {
- case XPT_SCSI_IO: /* Execute the requested I/O operation */
- case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */
- if (((cb = scsi_low_get_ccb()) == NULL)) {
- ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
- xpt_done(ccb);
- return;
- }
+ cb->ti = ti;
+ cb->li = li;
+
+ scsi_low_ccb_message_assert(cb, msg);
- cb->ccb = ccb;
- cb->ccb_tag = SCSI_LOW_UNKTAG;
- cb->bp = (struct buf *)NULL;
- cb->ti = ti = slp->sl_ti[target];
- cb->li = scsi_low_alloc_li(ti, ccb->ccb_h.target_lun, 1);
- cb->ccb_flags = 0;
- cb->ccb_rcnt = 0;
+ cb->ccb_otag = cb->ccb_tag = SCSI_LOW_UNKTAG;
+ scsi_low_alloc_qtag(cb);
- s = splcam();
+ cb->ccb_flags = flags | CCB_STARTQ;
+ cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
+ cb->ccb_error |= PENDINGIO;
+ if ((flags & CCB_URGENT) != 0)
+ {
+ TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
+ }
+ else
+ {
TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain);
+ }
- if (slp->sl_nexus == NULL) {
- scsi_low_start(slp);
- }
+ slp->sl_nio ++;
- splx(s);
- break;
- case XPT_EN_LUN: /* Enable LUN as a target */
- case XPT_TARGET_IO: /* Execute target I/O request */
- case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */
- case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/
- case XPT_ABORT: /* Abort the specified CCB */
- /* XXX Implement */
- ccb->ccb_h.status = CAM_REQ_INVALID;
- xpt_done(ccb);
- break;
- case XPT_SET_TRAN_SETTINGS:
- /* XXX Implement */
- ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
- xpt_done(ccb);
- break;
- case XPT_GET_TRAN_SETTINGS: {
- struct ccb_trans_settings *cts;
- struct targ_info *ti;
- int lun = ccb->ccb_h.target_lun;
- /*int s;*/
+ if (slp->sl_Tnexus == NULL)
+ scsi_low_start(slp);
+ return 0;
+}
- cts = &ccb->cts;
- ti = slp->sl_ti[ccb->ccb_h.target_id];
- s = splcam();
- li = LIST_FIRST(&ti->ti_litab);
- if (li != NULL && li->li_lun != lun)
- while ((li = LIST_NEXT(li, lun_chain)) != NULL)
- if (li->li_lun == lun)
- break;
- if (li != NULL && (cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
- if (li->li_cfgflags & SCSI_LOW_DISC)
- cts->flags = CCB_TRANS_DISC_ENB;
- else
- cts->flags = 0;
- if (li->li_cfgflags & SCSI_LOW_QTAG)
- cts->flags |= CCB_TRANS_TAG_ENB;
+static int
+scsi_low_message_enqueue(slp, ti, li, flags)
+ struct scsi_low_softc *slp;
+ struct targ_info *ti;
+ struct lun_info *li;
+ u_int flags;
+{
+ struct slccb *cb;
+ u_int tmsgflags;
- cts->sync_period = ti->ti_maxsynch.period;
- cts->sync_offset = ti->ti_maxsynch.offset;
- cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ tmsgflags = ti->ti_setup_msg;
+ ti->ti_setup_msg = 0;
- cts->valid = CCB_TRANS_SYNC_RATE_VALID
- | CCB_TRANS_SYNC_OFFSET_VALID
- | CCB_TRANS_BUS_WIDTH_VALID
- | CCB_TRANS_DISC_VALID
- | CCB_TRANS_TQ_VALID;
- ccb->ccb_h.status = CAM_REQ_CMP;
- } else
- ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+ flags |= CCB_NORETRY;
+ if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
+ return ENOMEM;
- splx(s);
- xpt_done(ccb);
- break;
- }
- case XPT_CALC_GEOMETRY: { /* not yet HN2 */
- struct ccb_calc_geometry *ccg;
- u_int32_t size_mb;
- u_int32_t secs_per_cylinder;
- int extended;
+ cb->osdep = NULL;
+ cb->bp = NULL;
+ scsi_low_enqueue(slp, ti, li, cb, flags, tmsgflags);
+ return 0;
+}
- extended = 1;
- ccg = &ccb->ccg;
- size_mb = ccg->volume_size
- / ((1024L * 1024L) / ccg->block_size);
-
- if (size_mb > 1024 && extended) {
- ccg->heads = 255;
- ccg->secs_per_track = 63;
- } else {
- ccg->heads = 64;
- ccg->secs_per_track = 32;
- }
- secs_per_cylinder = ccg->heads * ccg->secs_per_track;
- ccg->cylinders = ccg->volume_size / secs_per_cylinder;
- ccb->ccb_h.status = CAM_REQ_CMP;
- xpt_done(ccb);
- break;
- }
- case XPT_RESET_BUS: /* Reset the specified SCSI bus */
-#if 0
- scsi_low_bus_reset(slp);
-#endif
- ccb->ccb_h.status = CAM_REQ_CMP;
- xpt_done(ccb);
- break;
- case XPT_TERM_IO: /* Terminate the I/O process */
- /* XXX Implement */
- ccb->ccb_h.status = CAM_REQ_INVALID;
- xpt_done(ccb);
- break;
- case XPT_PATH_INQ: { /* Path routing inquiry */
- struct ccb_pathinq *cpi = &ccb->cpi;
-
- cpi->version_num = 1; /* XXX??? */
- cpi->hba_inquiry = PI_SDTR_ABLE;
- cpi->target_sprt = 0;
- cpi->hba_misc = 0;
- cpi->hba_eng_cnt = 0;
- cpi->max_target = SCSI_LOW_NTARGETS - 1;
- cpi->max_lun = 7;
- cpi->initiator_id = 7; /* HOST_SCSI_ID */
- cpi->bus_id = cam_sim_bus(sim);
- cpi->base_transfer_speed = 3300;
- strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
- strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN);
- strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
- cpi->unit_number = cam_sim_unit(sim);
- cpi->ccb_h.status = CAM_REQ_CMP;
- xpt_done(ccb);
- break;
- }
- default:
- printf("scsi_low: non support func_code = %d ", ccb->ccb_h.func_code);
- ccb->ccb_h.status = CAM_REQ_INVALID;
- xpt_done(ccb);
- break;
- }
+/**************************************************************
+ * Generic Start & Done
+ **************************************************************/
+#define SLSC_MODE_SENSE_SHORT 0x1a
+static u_int8_t ss_cmd[6] = {START_STOP, 0, 0, 0, SSS_START, 0};
+static u_int8_t sms_cmd[6] = {SLSC_MODE_SENSE_SHORT, 0x08, 0x0a, 0,
+ sizeof(struct scsi_low_mode_sense_data), 0};
+static u_int8_t inq_cmd[6] = {INQUIRY, 0, 0, 0,
+ sizeof(struct scsi_low_inq_data), 0};
+static u_int8_t unit_ready_cmd[6];
+static int scsi_low_setup_start __P((struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *));
+static int scsi_low_sense_abort_start __P((struct scsi_low_softc *, struct targ_info *, struct lun_info *, struct slccb *));
+static int scsi_low_resume __P((struct scsi_low_softc *));
+
+static void
+scsi_low_unit_ready_cmd(cb)
+ struct slccb *cb;
+{
+
+ cb->ccb_scp.scp_cmd = unit_ready_cmd;
+ cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd);
+ cb->ccb_scp.scp_datalen = 0;
+ cb->ccb_scp.scp_direction = SCSI_LOW_READ;
+ cb->ccb_tcmax = 15;
}
-#else /* !CAM */
+
static int
-scsi_low_scsi_cmd(xs)
- struct scsipi_xfer *xs;
-{
- struct scsi_low_softc *slp = xs->sc_link->adapter_softc;
+scsi_low_sense_abort_start(slp, ti, li, cb)
+ struct scsi_low_softc *slp;
struct targ_info *ti;
+ struct lun_info *li;
struct slccb *cb;
- int s, lun, timeo;
+{
- if (slp->sl_cfgflags & CFG_NOATTEN)
+ cb->ccb_scp.scp_cmdlen = 6;
+ SCSI_LOW_BZERO(cb->ccb_scsi_cmd, cb->ccb_scp.scp_cmdlen);
+ cb->ccb_scsi_cmd[0] = REQUEST_SENSE;
+ cb->ccb_scsi_cmd[4] = sizeof(cb->ccb_sense);
+ cb->ccb_scp.scp_cmd = cb->ccb_scsi_cmd;
+ cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense;
+ cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense);
+ cb->ccb_scp.scp_direction = SCSI_LOW_READ;
+ cb->ccb_tcmax = 15;
+ scsi_low_ccb_message_clear(cb);
+ if ((cb->ccb_flags & CCB_CLEARQ) != 0)
{
- if (xs->sc_link->scsipi_scsi.lun > 0)
- {
- xs->error = XS_DRIVER_STUFFUP;
- return COMPLETE;
- }
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
+ }
+ else
+ {
+ SCSI_LOW_BZERO(&cb->ccb_sense, sizeof(cb->ccb_sense));
+#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE
+ scsi_low_assert_msg(slp, ti, ti->ti_setup_msg_done, 0);
+#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
}
- if ((cb = scsi_low_get_ccb(xs->flags & SCSI_NOSLEEP)) == NULL)
- return TRY_AGAIN_LATER;
-
- lun = xs->sc_link->scsipi_scsi.lun;
- cb->xs = xs;
- cb->ccb_tag = SCSI_LOW_UNKTAG;
- cb->ti = ti = slp->sl_ti[xs->sc_link->scsipi_scsi.target];
- cb->li = scsi_low_alloc_li(ti, lun, 1);
- cb->ccb_flags = 0;
- cb->ccb_rcnt = 0;
-
- s = splbio();
+ return SCSI_LOW_START_NO_QTAG;
+}
- TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain);
- if (slp->sl_nexus == NULL)
- scsi_low_start(slp);
+static int
+scsi_low_setup_start(slp, ti, li, cb)
+ struct scsi_low_softc *slp;
+ struct targ_info *ti;
+ struct lun_info *li;
+ struct slccb *cb;
+{
- if ((xs->flags & SCSI_POLL) == 0)
+ switch(li->li_state)
{
- splx(s);
- return SUCCESSFULLY_QUEUED;
- }
+ case SCSI_LOW_LUN_SLEEP:
+ scsi_low_unit_ready_cmd(cb);
+ break;
+
+ case SCSI_LOW_LUN_START:
+ cb->ccb_scp.scp_cmd = ss_cmd;
+ cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd);
+ cb->ccb_scp.scp_datalen = 0;
+ cb->ccb_scp.scp_direction = SCSI_LOW_READ;
+ cb->ccb_tcmax = 30;
+ break;
-#define SCSI_LOW_POLL_INTERVAL 1000 /* 1 ms */
- timeo = xs->timeout * (1000 / SCSI_LOW_POLL_INTERVAL);
+ case SCSI_LOW_LUN_INQ:
+ cb->ccb_scp.scp_cmd = inq_cmd;
+ cb->ccb_scp.scp_cmdlen = sizeof(inq_cmd);
+ cb->ccb_scp.scp_data = (u_int8_t *)&li->li_inq;
+ cb->ccb_scp.scp_datalen = sizeof(li->li_inq);
+ cb->ccb_scp.scp_direction = SCSI_LOW_READ;
+ cb->ccb_tcmax = 15;
+ break;
- while ((xs->flags & ITSDONE) == 0 && timeo -- > 0)
- {
- delay(SCSI_LOW_POLL_INTERVAL);
- (*slp->sl_funcs->scsi_low_poll) (slp);
- }
+ case SCSI_LOW_LUN_MODEQ:
+ cb->ccb_scp.scp_cmd = sms_cmd;
+ cb->ccb_scp.scp_cmdlen = sizeof(sms_cmd);
+ cb->ccb_scp.scp_data = (u_int8_t *)&li->li_sms;
+ cb->ccb_scp.scp_datalen = sizeof(li->li_sms);
+ cb->ccb_scp.scp_direction = SCSI_LOW_READ;
+ cb->ccb_tcmax = 15;
+ return SCSI_LOW_START_QTAG;
- if ((xs->flags & ITSDONE) == 0)
- {
- cb->ccb_error |= (TIMEOUTIO | ABORTIO);
- SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL);
- scsi_low_disconnected(slp, ti);
- scsi_low_init(slp, SCSI_LOW_RESTART_HARD);
+ default:
+ panic("%s: no setup phase\n", slp->sl_xname);
}
- scsipi_done(xs);
- splx(s);
- return COMPLETE;
+ return SCSI_LOW_START_NO_QTAG;
}
-#endif
-
-/**************************************************************
- * Start & Done
- **************************************************************/
-#ifdef __NetBSD__
-static struct scsipi_start_stop ss_cmd = { START_STOP, 0, {0,0,}, SSS_START, };
-static struct scsipi_test_unit_ready unit_ready_cmd;
-#endif
-#ifdef __FreeBSD__
-static struct scsi_start_stop_unit ss_cmd = { START_STOP, 0, {0,0,}, SSS_START, };
-static struct scsi_test_unit_ready unit_ready_cmd;
-#endif
-static void scsi_low_unit_ready_cmd __P((struct slccb *));
-static void
-scsi_low_unit_ready_cmd(cb)
- struct slccb *cb;
+static int
+scsi_low_resume(slp)
+ struct scsi_low_softc *slp;
{
- cb->ccb_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd;
- cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd);
- cb->ccb_scp.scp_datalen = 0;
- cb->ccb_scp.scp_direction = SCSI_LOW_READ;
- cb->ccb_tcmax = 15;
+ if (slp->sl_flags & HW_RESUME)
+ return EJUSTRETURN;
+ slp->sl_flags &= ~HW_POWDOWN;
+ if (slp->sl_funcs->scsi_low_power != NULL)
+ {
+ slp->sl_flags |= HW_RESUME;
+ slp->sl_rstep = 0;
+ (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE);
+ (*slp->sl_osdep_fp->scsi_low_osdep_timeout)
+ (slp, SCSI_LOW_TIMEOUT_CH_ENGAGE,
+ SCSI_LOW_TIMEOUT_START);
+ return EJUSTRETURN;
+ }
+ return 0;
}
static void
scsi_low_start(slp)
struct scsi_low_softc *slp;
{
-#ifdef CAM
- union ccb *ccb;
-#else
- struct scsipi_xfer *xs;
-#endif
struct targ_info *ti;
struct lun_info *li;
struct slccb *cb;
int rv;
- /* check hardware exists ? */
- if ((slp->sl_flags & HW_INACTIVE) != 0)
+ /* check hardware exists or under initializations ? */
+ if ((slp->sl_flags & (HW_INACTIVE | HW_INITIALIZING)) != 0)
return;
/* check hardware power up ? */
@@ -903,155 +2442,95 @@ scsi_low_start(slp)
slp->sl_active ++;
if (slp->sl_flags & (HW_POWDOWN | HW_RESUME))
{
- if (slp->sl_flags & HW_RESUME)
- return;
- slp->sl_flags &= ~HW_POWDOWN;
- if (slp->sl_funcs->scsi_low_power != NULL)
- {
- slp->sl_flags |= HW_RESUME;
- slp->sl_rstep = 0;
- (*slp->sl_funcs->scsi_low_power)
- (slp, SCSI_LOW_ENGAGE);
-#ifdef __FreeBSD__
- slp->engage_ch =
-#endif
- timeout(scsi_low_engage, slp, 1);
+ if (scsi_low_resume(slp) == EJUSTRETURN)
return;
- }
}
}
/* setup nexus */
#ifdef SCSI_LOW_DIAGNOSTIC
- ti = slp->sl_nexus;
- if (ti != NULL)
+ if (slp->sl_Tnexus || slp->sl_Lnexus || slp->sl_Qnexus)
{
scsi_low_info(slp, NULL, "NEXUS INCOSISTENT");
- panic("%s: inconsistent(target)\n", slp->sl_xname);
+ panic("%s: inconsistent\n", slp->sl_xname);
}
#endif /* SCSI_LOW_DIAGNOSTIC */
- TAILQ_FOREACH(cb, &slp->sl_start, ccb_chain)
+ for (cb = TAILQ_FIRST(&slp->sl_start); cb != NULL;
+ cb = TAILQ_NEXT(cb, ccb_chain))
{
- ti = cb->ti;
li = cb->li;
- if (ti->ti_phase == PH_NULL)
- goto scsi_low_cmd_start;
- if (ti->ti_phase == PH_DISC && li->li_disc < li->li_maxnexus)
+
+ if (li->li_disc == 0)
+ {
goto scsi_low_cmd_start;
+ }
+ else if (li->li_nqio > 0)
+ {
+ if (li->li_nqio < li->li_maxnqio ||
+ (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
+ goto scsi_low_cmd_start;
+ }
}
return;
scsi_low_cmd_start:
-#ifdef CAM
- ccb = cb->ccb;
-#else
- xs = cb->xs;
-#endif
-#ifdef SCSI_LOW_DIAGNOSTIC
- if (ti->ti_nexus != NULL || ti->ti_li != NULL)
- {
- scsi_low_info(slp, NULL, "NEXUS INCOSISTENT");
- panic("%s: inconsistent(lun or ccb)\n", slp->sl_xname);
- }
-#endif /* SCSI_LOW_DIAGNOSTIC */
+ cb->ccb_flags &= ~CCB_STARTQ;
+ TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
+ ti = cb->ti;
/* clear all error flag bits (for restart) */
cb->ccb_error = 0;
+ cb->ccb_datalen = -1;
+ cb->ccb_scp.scp_status = ST_UNKNOWN;
/* setup nexus pointer */
- ti->ti_nexus = cb;
- ti->ti_li = li;
- slp->sl_nexus = ti;
+ slp->sl_Qnexus = cb;
+ slp->sl_Lnexus = li;
+ slp->sl_Tnexus = ti;
/* initialize msgsys */
scsi_low_init_msgsys(slp, ti);
- /* target lun state check */
-#ifdef CAM
- li->li_maxstate = UNIT_OK;
-#else
- if ((xs->flags & SCSI_POLL) != 0)
- li->li_maxstate = UNIT_NEGSTART;
- else
- li->li_maxstate = UNIT_OK;
-#endif
-
- /* exec cmds */
-scsi_low_cmd_exec:
- if ((cb->ccb_flags & CCB_SENSE) != 0)
- {
- memset(&cb->ccb_sense, 0, sizeof(cb->ccb_sense));
- memset(&cb->ccb_sense_cmd, 0, sizeof(cb->ccb_sense_cmd));
- cb->ccb_sense_cmd.opcode = REQUEST_SENSE;
- cb->ccb_sense_cmd.byte2 = (li->li_lun << 5);
- cb->ccb_sense_cmd.length = sizeof(cb->ccb_sense);
- cb->ccb_scp.scp_cmd = (u_int8_t *) &cb->ccb_sense_cmd;
- cb->ccb_scp.scp_cmdlen = sizeof(cb->ccb_sense_cmd);
- cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense;
- cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense);
- cb->ccb_scp.scp_direction = SCSI_LOW_READ;
- cb->ccb_tcmax = 15;
- }
- else if (li->li_state >= li->li_maxstate)
+ /* exec cmd */
+ if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
{
-#ifdef CAM
- cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes;
- cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len;
- cb->ccb_scp.scp_data = ccb->csio.data_ptr;
- cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len;
- if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
- cb->ccb_scp.scp_direction = SCSI_LOW_WRITE;
- else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */
- cb->ccb_scp.scp_direction = SCSI_LOW_READ;
- cb->ccb_tcmax = (ccb->ccb_h.timeout >> 10);
-#else
- cb->ccb_scp.scp_cmd = (u_int8_t *) xs->cmd;
- cb->ccb_scp.scp_cmdlen = xs->cmdlen;
- cb->ccb_scp.scp_data = xs->data;
- cb->ccb_scp.scp_datalen = xs->datalen;
- cb->ccb_scp.scp_direction = (xs->flags & SCSI_DATA_OUT) ?
- SCSI_LOW_WRITE : SCSI_LOW_READ;
- cb->ccb_tcmax = (xs->timeout >> 10);
-#endif
-
+ /* CA state or forced abort */
+ rv = scsi_low_sense_abort_start(slp, ti, li, cb);
}
- else switch(li->li_state)
+ else if (li->li_state >= SCSI_LOW_LUN_OK)
{
- case UNIT_SLEEP:
- scsi_low_unit_ready_cmd(cb);
- break;
-
- case UNIT_START:
- cb->ccb_scp.scp_cmd = (u_int8_t *) &ss_cmd;
- cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd);
- cb->ccb_scp.scp_datalen = 0;
- cb->ccb_scp.scp_direction = SCSI_LOW_READ;
- cb->ccb_tcmax = 30;
- break;
-
- case UNIT_SYNCH:
- if (ti->ti_maxsynch.offset > 0)
+ cb->ccb_flags &= ~CCB_INTERNAL;
+ rv = (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, cb);
+ if (cb->ccb_msgoutflag != 0)
{
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0);
- scsi_low_unit_ready_cmd(cb);
- break;
+ scsi_low_ccb_message_exec(slp, cb);
}
- li->li_state = UNIT_WIDE;
+ }
+ else
+ {
+ cb->ccb_flags |= CCB_INTERNAL;
+ rv = scsi_low_setup_start(slp, ti, li, cb);
+ }
- case UNIT_WIDE:
-#ifdef SCSI_LOW_SUPPORT_WIDE
- if (ti->ti_width > 0)
- {
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0);
- scsi_low_unit_ready_cmd(cb);
- break;
- }
-#endif /* SCSI_LOW_SUPPORT_WIDE */
- li->li_state = UNIT_OK;
+ /* allocate qtag */
+#define SCSI_LOW_QTAG_OK (SCSI_LOW_QTAG | SCSI_LOW_DISC)
- case UNIT_OK:
- goto scsi_low_cmd_exec;
+ if (rv == SCSI_LOW_START_QTAG &&
+ (li->li_flags & SCSI_LOW_QTAG_OK) == SCSI_LOW_QTAG_OK &&
+ li->li_maxnqio > 0)
+ {
+ u_int qmsg;
+
+ scsi_low_activate_qtag(cb);
+ if ((scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
+ SCSI_LOW_CMD_ORDERED_QTAG) != 0)
+ qmsg = SCSI_LOW_MSG_ORDERED_QTAG;
+ else if ((cb->ccb_flags & CCB_URGENT) != 0)
+ qmsg = SCSI_LOW_MSG_HEAD_QTAG;
+ else
+ qmsg = SCSI_LOW_MSG_SIMPLE_QTAG;
+ scsi_low_assert_msg(slp, ti, qmsg, 0);
}
/* timeout */
@@ -1066,8 +2545,17 @@ scsi_low_cmd_exec:
slp->sl_scp = cb->ccb_sscp;
slp->sl_error = cb->ccb_error;
+ /* assert always an identify msg */
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
+
+ /* debug section */
+#ifdef SCSI_LOW_DIAGNOSTIC
+ scsi_low_msg_log_init(&ti->ti_log_msgin);
+ scsi_low_msg_log_init(&ti->ti_log_msgout);
+#endif /* SCSI_LOW_DIAGNOSTIC */
+
/* selection start */
- slp->sl_selid = ti;
+ slp->sl_selid = cb;
rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb));
if (rv == SCSI_LOW_START_OK)
{
@@ -1077,245 +2565,339 @@ scsi_low_cmd_exec:
return;
}
+ scsi_low_arbit_fail(slp, cb);
#ifdef SCSI_LOW_STATICS
scsi_low_statics.nexus_fail ++;
#endif /* SCSI_LOW_STATICS */
- SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
- scsi_low_clear_nexus(slp, ti);
}
void
-scsi_low_clear_nexus(slp, ti)
+scsi_low_arbit_fail(slp, cb)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+{
+ struct targ_info *ti = cb->ti;
+
+ scsi_low_deactivate_qtag(cb);
+ scsi_low_ccb_message_retry(cb);
+ cb->ccb_flags |= CCB_STARTQ;
+ TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
+
+ scsi_low_bus_release(slp, ti);
+
+ cb->ccb_selrcnt ++;
+ if (slp->sl_disc == 0)
+ {
+#ifdef SCSI_LOW_DIAGNOSTIC
+ printf("%s: try selection again\n", slp->sl_xname);
+#endif /* SCSI_LOW_DIAGNOSTIC */
+ slp->sl_retry_sel = 1;
+ }
+}
+
+static void
+scsi_low_bus_release(slp, ti)
struct scsi_low_softc *slp;
struct targ_info *ti;
{
+ if (ti->ti_disc > 0)
+ {
+ SCSI_LOW_SETUP_PHASE(ti, PH_DISC);
+ }
+ else
+ {
+ SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
+ }
+
/* clear all nexus pointer */
- ti->ti_nexus = NULL;
- ti->ti_li = NULL;
- slp->sl_nexus = NULL;
+ slp->sl_Qnexus = NULL;
+ slp->sl_Lnexus = NULL;
+ slp->sl_Tnexus = NULL;
/* clear selection assert */
slp->sl_selid = NULL;
/* clear nexus data */
- slp->sl_nexus_call = 0;
slp->sl_scp.scp_direction = SCSI_LOW_RWUNK;
+
+ /* clear phase change counter */
+ slp->sl_ph_count = 0;
}
static int
-scsi_low_done(slp, cb)
+scsi_low_setup_done(slp, cb)
struct scsi_low_softc *slp;
struct slccb *cb;
{
-#ifdef CAM
- union ccb *ccb;
-#else
- struct scsipi_xfer *xs;
-#endif
struct targ_info *ti;
struct lun_info *li;
ti = cb->ti;
li = cb->li;
-#ifdef CAM
- ccb = cb->ccb;
-#else
- xs = cb->xs;
-#endif
- if (cb->ccb_error == 0)
+
+ if (cb->ccb_rcnt >= slp->sl_max_retry)
+ {
+ cb->ccb_error |= ABORTIO;
+ return SCSI_LOW_DONE_COMPLETE;
+ }
+
+ /* XXX: special huck for selection timeout */
+ if (li->li_state == SCSI_LOW_LUN_SLEEP &&
+ (cb->ccb_error & SELTIMEOUTIO) != 0)
{
- if ((cb->ccb_flags & CCB_SENSE) != 0)
+ cb->ccb_error |= ABORTIO;
+ return SCSI_LOW_DONE_COMPLETE;
+ }
+
+ switch(li->li_state)
+ {
+ case SCSI_LOW_LUN_INQ:
+ if (cb->ccb_error != 0)
{
- cb->ccb_flags &= ~CCB_SENSE;
-#ifdef CAM
- memcpy(&ccb->csio.sense_data,
- &cb->ccb_sense,
- sizeof(ccb->csio.sense_data));
- ccb->ccb_h.status = CAM_AUTOSNS_VALID
- | CAM_REQ_CMP_ERR;
-#else
- xs->sense.scsi_sense = cb->ccb_sense;
- xs->error = XS_SENSE;
-#endif
+ li->li_diskflags &=
+ ~(SCSI_LOW_DISK_LINK | SCSI_LOW_DISK_QTAG);
+ if (li->li_lun > 0)
+ goto resume;
+ ti->ti_diskflags &=
+ ~(SCSI_LOW_DISK_SYNC | SCSI_LOW_DISK_WIDE);
}
- else switch (ti->ti_status)
+ else if ((li->li_inq.sd_version & 7) >= 2 ||
+ (li->li_inq.sd_len >= 4))
{
- case ST_GOOD:
- if (slp->sl_scp.scp_datalen == 0)
+ if ((li->li_inq.sd_support & 0x2) == 0)
+ li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
+ if ((li->li_inq.sd_support & 0x8) == 0)
+ li->li_diskflags &= ~SCSI_LOW_DISK_LINK;
+ if (li->li_lun > 0)
+ goto resume;
+ if ((li->li_inq.sd_support & 0x10) == 0)
+ ti->ti_diskflags &= ~SCSI_LOW_DISK_SYNC;
+ if ((li->li_inq.sd_support & 0x20) == 0)
+ ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_16;
+ if ((li->li_inq.sd_support & 0x40) == 0)
+ ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE_32;
+ }
+ else
+ {
+ li->li_diskflags &=
+ ~(SCSI_LOW_DISK_QTAG | SCSI_LOW_DISK_LINK);
+ if (li->li_lun > 0)
+ goto resume;
+ ti->ti_diskflags &= ~SCSI_LOW_DISK_WIDE;
+ }
+ ti->ti_flags_valid |= SCSI_LOW_TARG_FLAGS_DISK_VALID;
+resume:
+ scsi_low_calcf_target(ti);
+ scsi_low_calcf_lun(li);
+ break;
+
+ case SCSI_LOW_LUN_MODEQ:
+ if (cb->ccb_error != 0)
+ {
+ if (cb->ccb_error & SENSEIO)
{
-#ifdef CAM
- ccb->ccb_h.status = CAM_REQ_CMP;
-#else
- xs->error = XS_NOERROR;
-#endif
- break;
+#ifdef SCSI_LOW_DEBUG
+ if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE)
+ {
+ printf("SENSE: [%x][%x][%x][%x][%x]\n",
+ (u_int) cb->ccb_sense.error_code,
+ (u_int) cb->ccb_sense.segment,
+ (u_int) cb->ccb_sense.flags,
+ (u_int) cb->ccb_sense.add_sense_code,
+ (u_int) cb->ccb_sense.add_sense_code_qual);
+ }
+#endif /* SCSI_LOW_DEBUG */
}
+ else
+ {
+ li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
+ }
+ }
+ else if ((li->li_sms.sms_cmp.cmp_page & 0x3f) == 0x0a)
+ {
+ if (li->li_sms.sms_cmp.cmp_qc & 0x02)
+ li->li_qflags |= SCSI_LOW_QFLAG_CA_QCLEAR;
+ else
+ li->li_qflags &= ~SCSI_LOW_QFLAG_CA_QCLEAR;
+ if ((li->li_sms.sms_cmp.cmp_qc & 0x01) != 0)
+ li->li_diskflags &= ~SCSI_LOW_DISK_QTAG;
+ }
+ li->li_flags_valid |= SCSI_LOW_LUN_FLAGS_DISK_VALID;
+ scsi_low_calcf_lun(li);
+ break;
-#define SCSIPI_SCSI_CD_COMPLETELY_BUGGY "YES"
-#ifdef SCSIPI_SCSI_CD_COMPLETELY_BUGGY
-#ifdef CAM
- if (cb->bp == NULL &&
- slp->sl_scp.scp_datalen < cb->ccb_scp.scp_datalen)
-#else
- if (xs->bp == NULL &&
- slp->sl_scp.scp_datalen < cb->ccb_scp.scp_datalen)
-#endif
+ default:
+ break;
+ }
+
+ li->li_state ++;
+ if (li->li_state == SCSI_LOW_LUN_OK)
+ {
+ scsi_low_calcf_target(ti);
+ scsi_low_calcf_lun(li);
+ if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID &&
+ (slp->sl_show_result & SHOW_CALCF_RES) != 0)
+ {
+ scsi_low_calcf_show(li);
+ }
+ }
+
+ cb->ccb_rcnt --;
+ return SCSI_LOW_DONE_RETRY;
+}
+
+static int
+scsi_low_done(slp, cb)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+{
+ int rv;
+
+ if (cb->ccb_error == 0)
+ {
+ if ((cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) != 0)
+ {
+#ifdef SCSI_LOW_QCLEAR_AFTER_CA
+ /* XXX:
+ * SCSI-2 draft suggests
+ * page 0x0a QErr bit determins if
+ * the target aborts or continues
+ * the queueing io's after CA state resolved.
+ * However many targets seem not to support
+ * the page 0x0a. Thus we should manually clear the
+ * queuing io's after CA state.
+ */
+ if ((cb->ccb_flags & CCB_CLEARQ) == 0)
{
-#ifdef CAM
- ccb->ccb_h.status = CAM_REQ_CMP;
-#else
- xs->error = XS_NOERROR;
-#endif
+ cb->ccb_rcnt --;
+ cb->ccb_flags |= CCB_CLEARQ;
+ goto retry;
+ }
+#endif /* SCSI_LOW_QCLEAR_AFTER_CA */
+
+ if ((cb->ccb_flags & CCB_SENSE) != 0)
+ cb->ccb_error |= (SENSEIO | ABORTIO);
+ cb->ccb_flags &= ~(CCB_SENSE | CCB_CLEARQ);
+ }
+ else switch (cb->ccb_sscp.scp_status)
+ {
+ case ST_GOOD:
+ case ST_MET:
+ case ST_INTERGOOD:
+ case ST_INTERMET:
+ if (cb->ccb_datalen == 0 ||
+ cb->ccb_scp.scp_datalen == 0)
+ break;
+
+ if (cb->ccb_scp.scp_cmdlen > 0 &&
+ (scsi_low_cmd_flags[cb->ccb_scp.scp_cmd[0]] &
+ SCSI_LOW_CMD_RESIDUAL_CHK) == 0)
break;
- }
-#endif /* SCSIPI_SCSI_CD_COMPLETELY_BUGGY */
cb->ccb_error |= PDMAERR;
-#ifdef CAM
- ccb->ccb_h.status = CAM_UNREC_HBA_ERROR;
-#else
- xs->error = XS_DRIVER_STUFFUP;
-#endif
+ break;
+
+ case ST_BUSY:
+ case ST_QUEFULL:
+ cb->ccb_error |= (BUSYERR | STATERR);
+ break;
+
+ case ST_CONFLICT:
+ cb->ccb_error |= (STATERR | ABORTIO);
break;
case ST_CHKCOND:
- case ST_MET:
-#ifdef CAM
- if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) {
+ case ST_CMDTERM:
+ if (cb->ccb_flags & (CCB_AUTOSENSE | CCB_INTERNAL))
+ {
+ cb->ccb_rcnt --;
cb->ccb_flags |= CCB_SENSE;
goto retry;
}
- ccb->ccb_h.status = CAM_AUTOSENSE_FAIL | CAM_REQ_CMP_ERR;
- break;
-#else
- cb->ccb_flags |= CCB_SENSE;
- xs->error = XS_SENSE;
- goto retry;
-#endif
-
- case ST_BUSY:
- cb->ccb_error |= BUSYERR;
-#ifdef CAM
- ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
-#else
- xs->error = XS_BUSY;
-#endif
+ cb->ccb_error |= (UACAERR | STATERR | ABORTIO);
break;
+ case ST_UNKNOWN:
default:
cb->ccb_error |= FATALIO;
-#ifdef CAM
- ccb->ccb_h.status = CAM_UNREC_HBA_ERROR;
-#else
- xs->error = XS_DRIVER_STUFFUP;
-#endif
break;
}
}
else
{
- cb->ccb_flags &= ~CCB_SENSE;
- if (ti->ti_phase == PH_SELSTART)
- {
-#ifdef CAM
- ccb->ccb_h.status = CAM_CMD_TIMEOUT;
-#else
- xs->error = XS_TIMEOUT;
-#endif
- slp->sl_error |= SELTIMEOUTIO;
- if (li->li_state == UNIT_SLEEP)
- cb->ccb_error |= ABORTIO;
- }
- else
- {
-#ifdef CAM
- ccb->ccb_h.status = CAM_UNREC_HBA_ERROR;
-#else
- xs->error = XS_DRIVER_STUFFUP;
-#endif
- }
-
- if ((cb->ccb_error & ABORTIO) != 0)
+ if (cb->ccb_flags & CCB_SENSE)
{
- cb->ccb_rcnt = slp->sl_max_retry;
-#ifdef CAM
- ccb->ccb_h.status = CAM_REQ_ABORTED;
-#endif
+ cb->ccb_error |= (SENSEERR | ABORTIO);
}
+ cb->ccb_flags &= ~(CCB_CLEARQ | CCB_SENSE);
}
- /* target state check */
- if (li->li_state < li->li_maxstate)
+ /* internal ccb */
+ if ((cb->ccb_flags & CCB_INTERNAL) != 0)
{
- if (cb->ccb_rcnt < slp->sl_max_retry)
- {
- li->li_state ++;
- cb->ccb_rcnt = 0;
+ if (scsi_low_setup_done(slp, cb) == SCSI_LOW_DONE_RETRY)
goto retry;
- }
}
- /* internal retry check */
-#ifdef CAM
- if (ccb->ccb_h.status == CAM_REQ_CMP)
+ /* check a ccb msgout flag */
+ if (cb->ccb_omsgoutflag != 0)
{
- ccb->csio.resid = 0;
+#define SCSI_LOW_MSG_ABORT_OK (SCSI_LOW_MSG_ABORT | \
+ SCSI_LOW_MSG_ABORT_QTAG | \
+ SCSI_LOW_MSG_CLEAR_QTAG | \
+ SCSI_LOW_MSG_TERMIO)
+
+ if ((cb->ccb_omsgoutflag & SCSI_LOW_MSG_ABORT_OK) != 0)
+ {
+ cb->ccb_error |= ABORTIO;
+ }
}
- else
+
+ /* call OS depend done */
+ if (cb->osdep != NULL)
{
- if (((ccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) &&
- (cb->ccb_rcnt < slp->sl_max_retry))
+ rv = (*slp->sl_osdep_fp->scsi_low_osdep_done) (slp, cb);
+ if (rv == EJUSTRETURN)
goto retry;
-#else
- if (xs->error == XS_NOERROR)
- {
- xs->resid = 0;
}
- else
+ else if (cb->ccb_error != 0)
{
- if (xs->error != XS_SENSE &&
- cb->ccb_rcnt < slp->sl_max_retry)
- goto retry;
-#endif
+ if (cb->ccb_rcnt >= slp->sl_max_retry)
+ cb->ccb_error |= ABORTIO;
-#ifdef SCSI_LOW_WARNINGS
-#ifdef CAM
- if (cb->bp != NULL)
-#else
- if (xs->bp != NULL)
-#endif
- {
- scsi_low_print(slp, ti);
- printf("%s: WARNING: File system IO abort\n",
- slp->sl_xname);
- }
-#endif /* SCSI_LOW_WARNINGS */
+ if ((cb->ccb_flags & CCB_NORETRY) == 0 &&
+ (cb->ccb_error & ABORTIO) == 0)
+ goto retry;
}
-#ifdef CAM
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 0)
- ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
- ccb->csio.scsi_status = ti->ti_status;
- xpt_done(ccb);
-#else
- xs->flags |= ITSDONE;
- if ((xs->flags & SCSI_POLL) == 0)
- scsipi_done(xs);
-#endif
-
/* free our target */
- TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
+ {
+ printf(">> SCSI_LOW_DONE_COMPLETE ===============\n");
+ scsi_low_print(slp, NULL);
+ }
+#endif /* SCSI_LOW_DEBUG */
+
+ scsi_low_deactivate_qtag(cb);
+ scsi_low_dealloc_qtag(cb);
scsi_low_free_ccb(cb);
+ slp->sl_nio --;
return SCSI_LOW_DONE_COMPLETE;
retry:
- cb->ccb_rcnt ++;
- if (TAILQ_FIRST(&slp->sl_start) != cb)
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DONE, cb->ti->ti_id) != 0)
{
- TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
- TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
+ printf("** SCSI_LOW_DONE_RETRY ===============\n");
+ scsi_low_print(slp, NULL);
}
+#endif /* SCSI_LOW_DEBUG */
+
+ cb->ccb_rcnt ++;
+ scsi_low_deactivate_qtag(cb);
+ scsi_low_ccb_message_retry(cb);
return SCSI_LOW_DONE_RETRY;
}
@@ -1323,12 +2905,53 @@ retry:
* Reset
**************************************************************/
static void
-scsi_low_clear_ccb(cb)
- struct slccb *cb;
+scsi_low_reset_nexus_target(slp, ti, fdone)
+ struct scsi_low_softc *slp;
+ struct targ_info *ti;
+ int fdone;
{
+ struct lun_info *li;
- cb->ccb_flags &= ~CCB_SENSE;
- cb->ccb_tag = SCSI_LOW_UNKTAG;
+ for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
+ li = LIST_NEXT(li, lun_chain))
+ {
+ scsi_low_reset_nexus_lun(slp, li, fdone);
+ li->li_state = SCSI_LOW_LUN_SLEEP;
+ li->li_maxnqio = 0;
+ }
+
+ ti->ti_disc = 0;
+ ti->ti_setup_msg = 0;
+ ti->ti_setup_msg_done = 0;
+
+ ti->ti_osynch.offset = ti->ti_osynch.period = 0;
+ ti->ti_owidth = SCSI_LOW_BUS_WIDTH_8;
+
+ ti->ti_diskflags = SCSI_LOW_DISK_TFLAGS;
+ ti->ti_flags_valid &= ~SCSI_LOW_TARG_FLAGS_DISK_VALID;
+
+ if (slp->sl_funcs->scsi_low_targ_init != NULL)
+ {
+ ((*slp->sl_funcs->scsi_low_targ_init)
+ (slp, ti, SCSI_LOW_INFO_REVOKE));
+ }
+ scsi_low_calcf_target(ti);
+
+ for (li = LIST_FIRST(&ti->ti_litab); li != NULL;
+ li = LIST_NEXT(li, lun_chain))
+ {
+ li->li_flags = 0;
+
+ li->li_diskflags = SCSI_LOW_DISK_LFLAGS;
+ li->li_flags_valid &= ~SCSI_LOW_LUN_FLAGS_DISK_VALID;
+
+ if (slp->sl_funcs->scsi_low_lun_init != NULL)
+ {
+ ((*slp->sl_funcs->scsi_low_lun_init)
+ (slp, ti, li, SCSI_LOW_INFO_REVOKE));
+ }
+ scsi_low_calcf_lun(li);
+ }
}
static void
@@ -1337,57 +2960,40 @@ scsi_low_reset_nexus(slp, fdone)
int fdone;
{
struct targ_info *ti;
- struct lun_info *li;
- struct slccb *cb, *ncb;
+ struct slccb *cb, *topcb;
- /* current nexus */
- ti = slp->sl_nexus;
- if (ti != NULL && (cb = ti->ti_nexus) != NULL)
+ if ((cb = slp->sl_Qnexus) != NULL)
{
- scsi_low_clear_ccb(cb);
- if (fdone != 0 && cb->ccb_rcnt ++ >= slp->sl_max_retry)
- {
- cb->ccb_error |= FATALIO;
- scsi_low_done(slp, cb);
- }
+ topcb = scsi_low_revoke_ccb(slp, cb, fdone);
}
-
- /* disconnected nexus */
- TAILQ_FOREACH(ti, &slp->sl_titab, ti_chain)
+ else
{
- for (cb = TAILQ_FIRST(&ti->ti_discq); cb != NULL; cb = ncb)
- {
- ncb = TAILQ_NEXT(cb, ccb_chain);
- TAILQ_REMOVE(&ti->ti_discq, cb, ccb_chain);
- TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
- scsi_low_clear_ccb(cb);
- if (fdone != 0 && cb->ccb_rcnt ++ >= slp->sl_max_retry)
- {
- cb->ccb_error |= FATALIO;
- scsi_low_done(slp, cb);
- }
- }
-
- LIST_FOREACH(li, &ti->ti_litab, lun_chain)
- {
- li->li_state = UNIT_SLEEP;
- li->li_disc = 0;
- ((*slp->sl_funcs->scsi_low_targ_init) (slp, ti));
- scsi_low_calcf(ti, li);
- }
+ topcb = NULL;
+ }
+ for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
+ ti = TAILQ_NEXT(ti, ti_chain))
+ {
+ scsi_low_reset_nexus_target(slp, ti, fdone);
+ scsi_low_bus_release(slp, ti);
scsi_low_init_msgsys(slp, ti);
- scsi_low_clear_nexus(slp, ti);
- SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
}
- slp->sl_flags &= ~HW_PDMASTART;
+ if (topcb != NULL)
+ {
+ topcb->ccb_flags |= CCB_STARTQ;
+ TAILQ_INSERT_HEAD(&slp->sl_start, topcb, ccb_chain);
+ }
+
slp->sl_disc = 0;
+ slp->sl_retry_sel = 0;
+ slp->sl_flags &= ~HW_PDMASTART;
}
/* misc */
static int tw_pos;
static char tw_chars[] = "|/-\\";
+#define TWIDDLEWAIT 10000
static void
scsi_low_twiddle_wait(void)
@@ -1396,7 +3002,7 @@ scsi_low_twiddle_wait(void)
cnputc('\b');
cnputc(tw_chars[tw_pos++]);
tw_pos %= (sizeof(tw_chars) - 1);
- delay(TWIDDLEWAIT);
+ SCSI_LOW_DELAY(TWIDDLEWAIT);
}
void
@@ -1437,21 +3043,6 @@ scsi_low_restart(slp, flags, s)
**************************************************************/
#define MSGCMD_LUN(msg) (msg & 0x07)
-static struct lun_info *
-scsi_low_establish_lun(ti, lun)
- struct targ_info *ti;
- int lun;
-{
- struct lun_info *li;
-
- li = scsi_low_alloc_li(ti, lun, 0);
- if (li == NULL)
- return li;
-
- ti->ti_li = li;
- return li;
-}
-
static struct slccb *
scsi_low_establish_ccb(ti, li, tag)
struct targ_info *ti;
@@ -1461,12 +3052,12 @@ scsi_low_establish_ccb(ti, li, tag)
struct scsi_low_softc *slp = ti->ti_sc;
struct slccb *cb;
- /*
- * Search ccb matching with lun and tag.
- */
- cb = TAILQ_FIRST(&ti->ti_discq);
+ if (li == NULL)
+ return NULL;
+
+ cb = TAILQ_FIRST(&li->li_discq);
for ( ; cb != NULL; cb = TAILQ_NEXT(cb, ccb_chain))
- if (cb->li == li && cb->ccb_tag == tag)
+ if (cb->ccb_tag == tag)
goto found;
return cb;
@@ -1474,19 +3065,43 @@ scsi_low_establish_ccb(ti, li, tag)
* establish our ccb nexus
*/
found:
- TAILQ_REMOVE(&ti->ti_discq, cb, ccb_chain);
- TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
- ti->ti_nexus = cb;
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
+ {
+ printf("%s: nexus(0x%lx) abort check start\n",
+ slp->sl_xname, (u_long) cb);
+ cb->ccb_flags |= (CCB_NORETRY | CCB_SILENT);
+ scsi_low_revoke_ccb(slp, cb, 1);
+ return NULL;
+ }
+
+ if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id) != 0)
+ {
+ if (cb->ccb_omsgoutflag == 0)
+ scsi_low_ccb_message_assert(cb, SCSI_LOW_MSG_NOOP);
+ }
+#endif /* SCSI_LOW_DEBUG */
+
+ TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
+ cb->ccb_flags &= ~CCB_DISCQ;
+ slp->sl_Qnexus = cb;
slp->sl_scp = cb->ccb_sscp;
slp->sl_error |= cb->ccb_error;
slp->sl_disc --;
+ ti->ti_disc --;
li->li_disc --;
/* inform "ccb nexus established" to the host driver */
- slp->sl_nexus_call = 1;
- (*slp->sl_funcs->scsi_low_establish_nexus) (slp, ti);
+ (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
+
+ /* check msg */
+ if (cb->ccb_msgoutflag != 0)
+ {
+ scsi_low_ccb_message_exec(slp, cb);
+ }
+
return cb;
}
@@ -1496,21 +3111,25 @@ scsi_low_reselected(slp, targ)
u_int targ;
{
struct targ_info *ti;
+ struct slccb *cb;
u_char *s;
/*
* Check select vs reselected collision.
*/
- if ((ti = slp->sl_selid) != NULL)
+ if ((cb = slp->sl_selid) != NULL)
{
- scsi_low_clear_nexus(slp, ti);
- SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
+ scsi_low_arbit_fail(slp, cb);
#ifdef SCSI_LOW_STATICS
scsi_low_statics.nexus_conflict ++;
#endif /* SCSI_LOW_STATICS */
}
- else if (slp->sl_nexus != NULL)
+
+ /*
+ * Check if no current active nexus.
+ */
+ if (slp->sl_Tnexus != NULL)
{
s = "host busy";
goto world_restart;
@@ -1529,25 +3148,23 @@ scsi_low_reselected(slp, targ)
* Check the target scsi status.
*/
ti = slp->sl_ti[targ];
- if (ti->ti_phase != PH_DISC)
+ if (ti->ti_phase != PH_DISC && ti->ti_phase != PH_NULL)
{
s = "phase mismatch";
goto world_restart;
}
/*
- * Setup lun and init msgsys
+ * Setup init msgsys
*/
slp->sl_error = 0;
scsi_low_init_msgsys(slp, ti);
/*
* Establish our target nexus
- * Remark: ccb and scsi pointer not yet restored
- * if lun != SCSI_LOW_UNKLUN.
*/
SCSI_LOW_SETUP_PHASE(ti, PH_RESEL);
- slp->sl_nexus = ti;
+ slp->sl_Tnexus = ti;
#ifdef SCSI_LOW_STATICS
scsi_low_statics.nexus_reselected ++;
#endif /* SCSI_LOW_STATICS */
@@ -1560,49 +3177,6 @@ world_restart:
return NULL;
}
-int
-scsi_low_disconnected(slp, ti)
- struct scsi_low_softc *slp;
- struct targ_info *ti;
-{
- struct slccb *cb = ti->ti_nexus;
-
- /* check phase completion */
- switch (slp->sl_msgphase)
- {
- case MSGPH_DISC:
- if (cb != NULL)
- {
- TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
- TAILQ_INSERT_TAIL(&ti->ti_discq, cb, ccb_chain);
- cb->ccb_error |= slp->sl_error;
- cb->li->li_disc ++;
- slp->sl_disc ++;
- }
- SCSI_LOW_SETUP_PHASE(ti, PH_DISC);
-#ifdef SCSI_LOW_STATICS
- scsi_low_statics.nexus_disconnected ++;
-#endif /* SCSI_LOW_STATICS */
- break;
-
- case MSGPH_NULL:
- slp->sl_error |= FATALIO;
-
- case MSGPH_CMDC:
- if (cb != NULL)
- {
- cb->ccb_error |= slp->sl_error;
- scsi_low_done(slp, cb);
- }
- SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
- break;
- }
-
- scsi_low_clear_nexus(slp, ti);
- scsi_low_start(slp);
- return 1;
-}
-
/**************************************************************
* cmd out pointer setup
**************************************************************/
@@ -1611,24 +3185,31 @@ scsi_low_cmd(slp, ti)
struct scsi_low_softc *slp;
struct targ_info *ti;
{
- struct slccb *cb = ti->ti_nexus;
+ struct slccb *cb = slp->sl_Qnexus;
+ slp->sl_ph_count ++;
if (cb == NULL)
{
/*
- * no slccb, abort!
+ * no ccb, abort!
*/
slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd;
slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd);
slp->sl_scp.scp_datalen = 0;
slp->sl_scp.scp_direction = SCSI_LOW_READ;
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
- scsi_low_info(slp, ti, "CMDOUT: slccb nexus not found");
+ slp->sl_error |= FATALIO;
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
+ SCSI_LOW_INFO(slp, ti, "CMDOUT: ccb nexus not found");
+ return EINVAL;
}
- else if (slp->sl_nexus_call == 0)
+ else
{
- slp->sl_nexus_call = 1;
- (*slp->sl_funcs->scsi_low_establish_nexus) (slp, ti);
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_CMDLNK_CHECK, ti->ti_id))
+ {
+ scsi_low_test_cmdlnk(slp, cb);
+ }
+#endif /* SCSI_LOW_DEBUG */
}
return 0;
}
@@ -1643,27 +3224,31 @@ scsi_low_data(slp, ti, bp, direction)
struct buf **bp;
int direction;
{
- struct slccb *cb = ti->ti_nexus;
+ struct slccb *cb = slp->sl_Qnexus;
- if (cb == NULL)
+ if (cb != NULL && direction == cb->ccb_sscp.scp_direction)
{
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
- scsi_low_info(slp, ti, "DATA PHASE: slccb nexus not found");
- return EINVAL;
+ *bp = cb->bp;
+ return 0;
}
- if (direction != cb->ccb_scp.scp_direction)
+ slp->sl_error |= (FATALIO | PDMAERR);
+ slp->sl_scp.scp_datalen = 0;
+ slp->sl_scp.scp_direction = direction;
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
+ if (ti->ti_ophase != ti->ti_phase)
{
- scsi_low_info(slp, ti, "DATA PHASE: xfer direction mismatch");
- return EINVAL;
+ char *s;
+
+ if (cb == NULL)
+ s = "DATA PHASE: ccb nexus not found";
+ else
+ s = "DATA PHASE: xfer direction mismatch";
+ SCSI_LOW_INFO(slp, ti, s);
}
-#ifdef CAM
- *bp = (cb == NULL) ? NULL : cb->bp;
-#else
- *bp = (cb->xs == NULL) ? NULL : cb->xs->bp;
-#endif
- return 0;
+ *bp = NULL;
+ return EINVAL;
}
/**************************************************************
@@ -1672,69 +3257,83 @@ scsi_low_data(slp, ti, bp, direction)
#define MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;}
#define MSGIN_PERIOD(ti) ((ti)->ti_msgin[3])
#define MSGIN_OFFSET(ti) ((ti)->ti_msgin[4])
+#define MSGIN_WIDTHP(ti) ((ti)->ti_msgin[3])
#define MSGIN_DATA_LAST 0x30
-static int scsi_low_errfunc_synch __P((struct targ_info *, u_int));
-static int scsi_low_errfunc_wide __P((struct targ_info *, u_int));
-static int scsi_low_errfunc_identify __P((struct targ_info *, u_int));
+static int scsi_low_errfunc_synch __P((struct scsi_low_softc *, u_int));
+static int scsi_low_errfunc_wide __P((struct scsi_low_softc *, u_int));
+static int scsi_low_errfunc_identify __P((struct scsi_low_softc *, u_int));
+static int scsi_low_errfunc_qtag __P((struct scsi_low_softc *, u_int));
-static int scsi_low_msgfunc_synch __P((struct targ_info *));
-static int scsi_low_msgfunc_wide __P((struct targ_info *));
-static int scsi_low_msgfunc_identify __P((struct targ_info *));
-static int scsi_low_msgfunc_user __P((struct targ_info *));
-static int scsi_low_msgfunc_abort __P((struct targ_info *));
+static int scsi_low_msgfunc_synch __P((struct scsi_low_softc *));
+static int scsi_low_msgfunc_wide __P((struct scsi_low_softc *));
+static int scsi_low_msgfunc_identify __P((struct scsi_low_softc *));
+static int scsi_low_msgfunc_abort __P((struct scsi_low_softc *));
+static int scsi_low_msgfunc_qabort __P((struct scsi_low_softc *));
+static int scsi_low_msgfunc_qtag __P((struct scsi_low_softc *));
+static int scsi_low_msgfunc_reset __P((struct scsi_low_softc *));
struct scsi_low_msgout_data {
u_int md_flags;
u_int8_t md_msg;
- int (*md_msgfunc) __P((struct targ_info *));
- int (*md_errfunc) __P((struct targ_info *, u_int));
+ int (*md_msgfunc) __P((struct scsi_low_softc *));
+ int (*md_errfunc) __P((struct scsi_low_softc *, u_int));
+#define MSG_RELEASE_ATN 0x0001
+ u_int md_condition;
};
struct scsi_low_msgout_data scsi_low_msgout_data[] = {
-/* 0 */ {SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_abort, NULL},
-/* 1 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL},
-/* 2 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL},
-/* 3 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL},
-/* 4 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL},
-/* 5 */ {SCSI_LOW_MSG_IDENTIFY, 0, scsi_low_msgfunc_identify, scsi_low_errfunc_identify},
-/* 6 */ {SCSI_LOW_MSG_SYNCH, 0, scsi_low_msgfunc_synch, scsi_low_errfunc_synch},
-/* 7 */ {SCSI_LOW_MSG_WIDE, 0, scsi_low_msgfunc_wide, scsi_low_errfunc_wide},
-/* 8 */ {SCSI_LOW_MSG_USER, 0, scsi_low_msgfunc_user, NULL},
-/* 9 */ {SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL},
-/* 10 */ {SCSI_LOW_MSG_ALL, 0},
+/* 0 */ {SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_reset, NULL, MSG_RELEASE_ATN},
+/* 1 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL, MSG_RELEASE_ATN},
+/* 2 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL, MSG_RELEASE_ATN},
+/* 3 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL, MSG_RELEASE_ATN},
+/* 4 */ {SCSI_LOW_MSG_IDENTIFY, MSG_IDENTIFY, scsi_low_msgfunc_identify, scsi_low_errfunc_identify, 0},
+/* 5 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
+/* 6 */ {SCSI_LOW_MSG_TERMIO, MSG_TERM_IO, NULL, NULL, MSG_RELEASE_ATN},
+/* 7 */ {SCSI_LOW_MSG_SIMPLE_QTAG, MSG_SIMPLE_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
+/* 8 */ {SCSI_LOW_MSG_ORDERED_QTAG, MSG_ORDERED_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
+/* 9 */{SCSI_LOW_MSG_HEAD_QTAG, MSG_HEAD_QTAG, scsi_low_msgfunc_qtag, scsi_low_errfunc_qtag, 0},
+/* 10 */ {SCSI_LOW_MSG_ABORT_QTAG, MSG_ABORT_QTAG, scsi_low_msgfunc_qabort, NULL, MSG_RELEASE_ATN},
+/* 11 */ {SCSI_LOW_MSG_CLEAR_QTAG, MSG_CLEAR_QTAG, scsi_low_msgfunc_abort, NULL, MSG_RELEASE_ATN},
+/* 12 */{SCSI_LOW_MSG_WIDE, MSG_EXTEND, scsi_low_msgfunc_wide, scsi_low_errfunc_wide, MSG_RELEASE_ATN},
+/* 13 */{SCSI_LOW_MSG_SYNCH, MSG_EXTEND, scsi_low_msgfunc_synch, scsi_low_errfunc_synch, MSG_RELEASE_ATN},
+/* 14 */{SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL, MSG_RELEASE_ATN},
+/* 15 */{SCSI_LOW_MSG_ALL, 0},
};
-static int scsi_low_msginfunc_ext __P((struct targ_info *));
-static int scsi_low_synch __P((struct targ_info *));
-static int scsi_low_msginfunc_msg_reject __P((struct targ_info *));
-static int scsi_low_msginfunc_rejop __P((struct targ_info *));
-static int scsi_low_msginfunc_rdp __P((struct targ_info *));
-static int scsi_low_msginfunc_sdp __P((struct targ_info *));
-static int scsi_low_msginfunc_disc __P((struct targ_info *));
-static int scsi_low_msginfunc_cc __P((struct targ_info *));
-static int scsi_low_msginfunc_parity __P((struct targ_info *));
-static int scsi_low_msginfunc_noop __P((struct targ_info *));
-static void scsi_low_retry_phase __P((struct targ_info *));
+static int scsi_low_msginfunc_ext __P((struct scsi_low_softc *));
+static int scsi_low_synch __P((struct scsi_low_softc *));
+static int scsi_low_wide __P((struct scsi_low_softc *));
+static int scsi_low_msginfunc_msg_reject __P((struct scsi_low_softc *));
+static int scsi_low_msginfunc_rejop __P((struct scsi_low_softc *));
+static int scsi_low_msginfunc_rp __P((struct scsi_low_softc *));
+static int scsi_low_msginfunc_sdp __P((struct scsi_low_softc *));
+static int scsi_low_msginfunc_disc __P((struct scsi_low_softc *));
+static int scsi_low_msginfunc_cc __P((struct scsi_low_softc *));
+static int scsi_low_msginfunc_lcc __P((struct scsi_low_softc *));
+static int scsi_low_msginfunc_parity __P((struct scsi_low_softc *));
+static int scsi_low_msginfunc_noop __P((struct scsi_low_softc *));
+static int scsi_low_msginfunc_simple_qtag __P((struct scsi_low_softc *));
+static int scsi_low_msginfunc_i_wide_residue __P((struct scsi_low_softc *));
struct scsi_low_msgin_data {
u_int md_len;
- int (*md_msgfunc) __P((struct targ_info *));
+ int (*md_msgfunc) __P((struct scsi_low_softc *));
};
struct scsi_low_msgin_data scsi_low_msgin_data[] = {
/* 0 */ {1, scsi_low_msginfunc_cc},
/* 1 */ {2, scsi_low_msginfunc_ext},
/* 2 */ {1, scsi_low_msginfunc_sdp},
-/* 3 */ {1, scsi_low_msginfunc_rdp},
+/* 3 */ {1, scsi_low_msginfunc_rp},
/* 4 */ {1, scsi_low_msginfunc_disc},
/* 5 */ {1, scsi_low_msginfunc_rejop},
/* 6 */ {1, scsi_low_msginfunc_rejop},
/* 7 */ {1, scsi_low_msginfunc_msg_reject},
/* 8 */ {1, scsi_low_msginfunc_noop},
/* 9 */ {1, scsi_low_msginfunc_parity},
-/* a */ {1, scsi_low_msginfunc_rejop},
-/* b */ {1, scsi_low_msginfunc_rejop},
+/* a */ {1, scsi_low_msginfunc_lcc},
+/* b */ {1, scsi_low_msginfunc_lcc},
/* c */ {1, scsi_low_msginfunc_rejop},
/* d */ {2, scsi_low_msginfunc_rejop},
/* e */ {1, scsi_low_msginfunc_rejop},
@@ -1755,10 +3354,10 @@ struct scsi_low_msgin_data scsi_low_msgin_data[] = {
/* 0x1d */ {1, scsi_low_msginfunc_rejop},
/* 0x1e */ {1, scsi_low_msginfunc_rejop},
/* 0x1f */ {1, scsi_low_msginfunc_rejop},
-/* 0x20 */ {2, scsi_low_msginfunc_rejop},
+/* 0x20 */ {2, scsi_low_msginfunc_simple_qtag},
/* 0x21 */ {2, scsi_low_msginfunc_rejop},
/* 0x22 */ {2, scsi_low_msginfunc_rejop},
-/* 0x23 */ {2, scsi_low_msginfunc_rejop},
+/* 0x23 */ {2, scsi_low_msginfunc_i_wide_residue},
/* 0x24 */ {2, scsi_low_msginfunc_rejop},
/* 0x25 */ {2, scsi_low_msginfunc_rejop},
/* 0x26 */ {2, scsi_low_msginfunc_rejop},
@@ -1774,35 +3373,16 @@ struct scsi_low_msgin_data scsi_low_msgin_data[] = {
/* 0x30 */ {1, scsi_low_msginfunc_rejop} /* default rej op */
};
-static void
-scsi_low_init_msgsys(slp, ti)
- struct scsi_low_softc *slp;
- struct targ_info *ti;
-{
-
- ti->ti_msginptr = 0;
- ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0;
- ti->ti_tflags &= ~TARG_ASSERT_ATN;
- SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL);
-}
-
/**************************************************************
* msgout
**************************************************************/
static int
-scsi_low_msgfunc_synch(ti)
- struct targ_info *ti;
+scsi_low_msgfunc_synch(slp)
+ struct scsi_low_softc *slp;
{
- struct lun_info *li = ti->ti_li;
+ struct targ_info *ti = slp->sl_Tnexus;
int ptr = ti->ti_msgoutlen;
- if (li == NULL)
- {
- scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0);
- return EINVAL;
- }
-
- ti->ti_msgoutstr[ptr + 0] = MSG_EXTEND;
ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN;
ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE;
ti->ti_msgoutstr[ptr + 3] = ti->ti_maxsynch.period;
@@ -1811,19 +3391,12 @@ scsi_low_msgfunc_synch(ti)
}
static int
-scsi_low_msgfunc_wide(ti)
- struct targ_info *ti;
+scsi_low_msgfunc_wide(slp)
+ struct scsi_low_softc *slp;
{
- struct lun_info *li = ti->ti_li;
+ struct targ_info *ti = slp->sl_Tnexus;
int ptr = ti->ti_msgoutlen;
- if (li == NULL)
- {
- scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0);
- return EINVAL;
- }
-
- ti->ti_msgoutstr[ptr + 0] = MSG_EXTEND;
ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN;
ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE;
ti->ti_msgoutstr[ptr + 3] = ti->ti_width;
@@ -1831,57 +3404,91 @@ scsi_low_msgfunc_wide(ti)
}
static int
-scsi_low_msgfunc_identify(ti)
- struct targ_info *ti;
+scsi_low_msgfunc_identify(slp)
+ struct scsi_low_softc *slp;
{
- int ptr = ti->ti_msgoutlen;;
+ struct targ_info *ti = slp->sl_Tnexus;
+ struct lun_info *li = slp->sl_Lnexus;
+ struct slccb *cb = slp->sl_Qnexus;
+ int ptr = ti->ti_msgoutlen;
+ u_int8_t msg;
- if (ti->ti_li == NULL)
+ msg = MSG_IDENTIFY;
+ if (cb == NULL)
{
- ti->ti_msgoutstr[ptr + 0] = 0x80;
- scsi_low_info(ti->ti_sc, ti, "MSGOUT: lun unknown");
- scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0);
+ slp->sl_error |= FATALIO;
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
+ SCSI_LOW_INFO(slp, ti, "MSGOUT: nexus unknown");
}
else
{
- ti->ti_msgoutstr[ptr + 0] = ID_MSG_SETUP(ti);
+ if (scsi_low_is_disconnect_ok(cb) != 0)
+ msg |= (MSG_IDENTIFY_DISCPRIV | li->li_lun);
+ else
+ msg |= li->li_lun;
+
+ if (ti->ti_phase == PH_MSGOUT)
+ {
+ (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
+ if (cb->ccb_tag == SCSI_LOW_UNKTAG)
+ {
+ (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
+ }
+ }
}
+ ti->ti_msgoutstr[ptr + 0] = msg;
return 1;
}
static int
-scsi_low_msgfunc_user(ti)
- struct targ_info *ti;
+scsi_low_msgfunc_abort(slp)
+ struct scsi_low_softc *slp;
+{
+
+ SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_ABORT);
+ return 1;
+}
+
+static int
+scsi_low_msgfunc_qabort(slp)
+ struct scsi_low_softc *slp;
{
-#ifdef SCSI_LOW_SUPPORT_USER_MSGOUT
- struct slccb *cb = ti->ti_nexus;
- int ptr = ti->ti_msgoutlen;;
- if (ti->ti_nexus == NULL)
+ SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_TERM);
+ return 1;
+}
+
+static int
+scsi_low_msgfunc_reset(slp)
+ struct scsi_low_softc *slp;
+{
+
+ SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_RESET);
+ return 1;
+}
+
+static int
+scsi_low_msgfunc_qtag(slp)
+ struct scsi_low_softc *slp;
+{
+ struct targ_info *ti = slp->sl_Tnexus;
+ struct slccb *cb = slp->sl_Qnexus;
+ int ptr = ti->ti_msgoutlen;
+
+ if (cb == NULL || cb->ccb_tag == SCSI_LOW_UNKTAG)
{
ti->ti_msgoutstr[ptr + 0] = MSG_NOOP;
return 1;
}
else
{
- bcopy(cb->msgout, ti->ti_msgoutstr + ptr, SCSI_LOW_MAX_MSGLEN);
- return cb->msgoutlen;
+ ti->ti_msgoutstr[ptr + 1] = (u_int8_t) cb->ccb_tag;
+ if (ti->ti_phase == PH_MSGOUT)
+ {
+ (*slp->sl_funcs->scsi_low_establish_ccb_nexus) (slp);
+ }
}
-#else /* !SCSI_LOW_SUPPORT_USER_MSGOUT */
- return 0;
-#endif /* !SCSI_LOW_SUPPORT_USER_MSGOUT */
-}
-
-static int
-scsi_low_msgfunc_abort(ti)
- struct targ_info *ti;
-{
- struct scsi_low_softc *slp = ti->ti_sc;
-
- /* The target should releases bus */
- SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC);
- slp->sl_error |= /* ABORTIO */ FATALIO;
- return 1;
+ return 2;
}
/*
@@ -1889,88 +3496,127 @@ scsi_low_msgfunc_abort(ti)
* responces in msgin (after msgout).
*/
static int
-scsi_low_errfunc_identify(ti, msgflags)
- struct targ_info *ti;
+scsi_low_errfunc_identify(slp, msgflags)
+ struct scsi_low_softc *slp;
u_int msgflags;
{
- struct lun_info *li = ti->ti_li;
- li->li_flags &= ~SCSI_LOW_DISC;
+ if (slp->sl_Lnexus != NULL)
+ {
+ slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_DISC;
+ scsi_low_calcf_lun(slp->sl_Lnexus);
+ }
return 0;
}
static int
-scsi_low_errfunc_synch(ti, msgflags)
- struct targ_info *ti;
+scsi_low_errfunc_synch(slp, msgflags)
+ struct scsi_low_softc *slp;
u_int msgflags;
{
+ struct targ_info *ti = slp->sl_Tnexus;
- /* XXX:
- * illegal behavior, however
- * there are buggy devices!
- */
MSGIN_PERIOD(ti) = 0;
MSGIN_OFFSET(ti) = 0;
- scsi_low_synch(ti);
+ scsi_low_synch(slp);
return 0;
}
static int
-scsi_low_errfunc_wide(ti, msgflags)
- struct targ_info *ti;
+scsi_low_errfunc_wide(slp, msgflags)
+ struct scsi_low_softc *slp;
+ u_int msgflags;
+{
+ struct targ_info *ti = slp->sl_Tnexus;
+
+ MSGIN_WIDTHP(ti) = 0;
+ scsi_low_wide(slp);
+ return 0;
+}
+
+static int
+scsi_low_errfunc_qtag(slp, msgflags)
+ struct scsi_low_softc *slp;
u_int msgflags;
{
- ti->ti_width = 0;
+
+ if ((msgflags & SCSI_LOW_MSG_REJECT) != 0)
+ {
+ if (slp->sl_Qnexus != NULL)
+ {
+ scsi_low_deactivate_qtag(slp->sl_Qnexus);
+ }
+ if (slp->sl_Lnexus != NULL)
+ {
+ slp->sl_Lnexus->li_cfgflags &= ~SCSI_LOW_QTAG;
+ scsi_low_calcf_lun(slp->sl_Lnexus);
+ }
+ printf("%s: scsi_low: qtag msg rejected\n", slp->sl_xname);
+ }
return 0;
}
+
int
-scsi_low_msgout(slp, ti)
+scsi_low_msgout(slp, ti, fl)
struct scsi_low_softc *slp;
struct targ_info *ti;
+ u_int fl;
{
struct scsi_low_msgout_data *mdp;
int len = 0;
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if (ti != slp->sl_Tnexus)
+ {
+ scsi_low_print(slp, NULL);
+ panic("scsi_low_msgout: Target nexus inconsistent");
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+
+ slp->sl_ph_count ++;
+ if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
+ {
+ printf("%s: too many phase changes\n", slp->sl_xname);
+ slp->sl_error |= FATALIO;
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
+ }
+
/* STEP I.
* Scsi phase changes.
* Previously msgs asserted are accepted by our target or
* processed by scsi_low_msgin.
* Thus clear all saved informations.
*/
- if (ti->ti_ophase != ti->ti_phase)
+ if ((fl & SCSI_LOW_MSGOUT_INIT) != 0)
{
ti->ti_omsgflags = 0;
ti->ti_emsgflags = 0;
}
-
+ else if (slp->sl_atten == 0)
+ {
/* STEP II.
* We did not assert attention, however still our target required
* msgs. Resend previous msgs.
*/
- if (ti->ti_ophase == PH_MSGOUT && !(ti->ti_tflags & TARG_ASSERT_ATN))
- {
ti->ti_msgflags |= ti->ti_omsgflags;
+ ti->ti_omsgflags = 0;
#ifdef SCSI_LOW_DIAGNOSTIC
printf("%s: scsi_low_msgout: retry msgout\n", slp->sl_xname);
#endif /* SCSI_LOW_DIAGNOSTIC */
}
- /*
- * OK. clear flags.
- */
- ti->ti_tflags &= ~TARG_ASSERT_ATN;
-
/* STEP III.
- * We have no msgs. send MSG_LOOP (OK?)
+ * We have no msgs. send MSG_NOOP (OK?)
*/
- if (scsi_low_is_msgout_continue(ti) == 0)
+ if (scsi_low_is_msgout_continue(ti, 0) == 0)
scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0);
/* STEP IV.
* Process all msgs
*/
ti->ti_msgoutlen = 0;
+ slp->sl_clear_atten = 0;
mdp = &scsi_low_msgout_data[0];
for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
{
@@ -1982,31 +3628,34 @@ scsi_low_msgout(slp, ti)
ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg;
if (mdp->md_msgfunc != NULL)
- len = (*mdp->md_msgfunc) (ti);
+ len = (*mdp->md_msgfunc) (slp);
else
len = 1;
+#ifdef SCSI_LOW_DIAGNOSTIC
+ scsi_low_msg_log_write(&ti->ti_log_msgout,
+ &ti->ti_msgoutstr[ti->ti_msgoutlen], len);
+#endif /* SCSI_LOW_DIAGNOSTIC */
+
ti->ti_msgoutlen += len;
- if ((slp->sl_cfgflags & CFG_MSGUNIFY) == 0 ||
+ if ((mdp->md_condition & MSG_RELEASE_ATN) != 0)
+ {
+ slp->sl_clear_atten = 1;
+ break;
+ }
+
+ if ((fl & SCSI_LOW_MSGOUT_UNIFY) == 0 ||
ti->ti_msgflags == 0)
break;
+
if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5)
break;
}
}
- if (scsi_low_is_msgout_continue(ti) != 0)
- {
-#ifdef SCSI_LOW_DIAGNOSTIC
- printf("SCSI_LOW_ATTENTION(msgout): 0x%x\n", ti->ti_msgflags);
-#endif /* SCSI_LOW_DIAGNOSTIC */
- scsi_low_attention(slp, ti);
- }
+ if (scsi_low_is_msgout_continue(ti, 0) == 0)
+ slp->sl_clear_atten = 1;
- /*
- * OK. advance old phase.
- */
- ti->ti_ophase = ti->ti_phase;
return ti->ti_msgoutlen;
}
@@ -2014,86 +3663,207 @@ scsi_low_msgout(slp, ti)
* msgin
**************************************************************/
static int
-scsi_low_msginfunc_noop(ti)
- struct targ_info *ti;
+scsi_low_msginfunc_noop(slp)
+ struct scsi_low_softc *slp;
{
return 0;
}
static int
-scsi_low_msginfunc_rejop(ti)
- struct targ_info *ti;
+scsi_low_msginfunc_rejop(slp)
+ struct scsi_low_softc *slp;
{
- struct scsi_low_softc *slp = ti->ti_sc;
+ struct targ_info *ti = slp->sl_Tnexus;
u_int8_t msg = ti->ti_msgin[0];
- printf("%s: MSGIN: msg 0x%x reject\n", slp->sl_xname, (u_int) msg);
+ printf("%s: MSGIN: msg 0x%x rejected\n", slp->sl_xname, (u_int) msg);
scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
return 0;
}
static int
-scsi_low_msginfunc_cc(ti)
- struct targ_info *ti;
+scsi_low_msginfunc_cc(slp)
+ struct scsi_low_softc *slp;
{
- struct scsi_low_softc *slp = ti->ti_sc;
+ struct lun_info *li;
SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC);
+
+ /* validate status */
+ if (slp->sl_Qnexus == NULL)
+ return ENOENT;
+
+ slp->sl_Qnexus->ccb_sscp.scp_status = slp->sl_scp.scp_status;
+ li = slp->sl_Lnexus;
+ switch (slp->sl_scp.scp_status)
+ {
+ case ST_GOOD:
+ li->li_maxnqio = li->li_maxnexus;
+ break;
+
+ case ST_CHKCOND:
+ li->li_maxnqio = 0;
+ if (li->li_qflags & SCSI_LOW_QFLAG_CA_QCLEAR)
+ scsi_low_reset_nexus_lun(slp, li, 0);
+ break;
+
+ case ST_BUSY:
+ li->li_maxnqio = 0;
+ break;
+
+ case ST_QUEFULL:
+ if (li->li_maxnexus >= li->li_nqio)
+ li->li_maxnexus = li->li_nqio - 1;
+ li->li_maxnqio = li->li_maxnexus;
+ break;
+
+ case ST_INTERGOOD:
+ case ST_INTERMET:
+ slp->sl_error |= MSGERR;
+ break;
+
+ default:
+ break;
+ }
return 0;
}
static int
-scsi_low_msginfunc_disc(ti)
+scsi_low_msginfunc_lcc(slp)
+ struct scsi_low_softc *slp;
+{
struct targ_info *ti;
+ struct lun_info *li;
+ struct slccb *ncb, *cb;
+
+ ti = slp->sl_Tnexus;
+ li = slp->sl_Lnexus;
+ if ((cb = slp->sl_Qnexus) == NULL)
+ goto bad;
+
+ cb->ccb_sscp.scp_status = slp->sl_scp.scp_status;
+ switch (slp->sl_scp.scp_status)
+ {
+ case ST_INTERGOOD:
+ case ST_INTERMET:
+ li->li_maxnqio = li->li_maxnexus;
+ break;
+
+ default:
+ slp->sl_error |= MSGERR;
+ break;
+ }
+
+ if ((li->li_flags & SCSI_LOW_LINK) == 0)
+ goto bad;
+
+ cb->ccb_error |= slp->sl_error;
+ if (cb->ccb_error != 0)
+ goto bad;
+
+ for (ncb = TAILQ_FIRST(&slp->sl_start); ncb != NULL;
+ ncb = TAILQ_NEXT(ncb, ccb_chain))
+ {
+ if (ncb->li == li)
+ goto cmd_link_start;
+ }
+
+
+bad:
+ SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_LCTERM);
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
+ return EIO;
+
+cmd_link_start:
+ ncb->ccb_flags &= ~CCB_STARTQ;
+ TAILQ_REMOVE(&slp->sl_start, ncb, ccb_chain);
+
+ scsi_low_dealloc_qtag(ncb);
+ ncb->ccb_tag = cb->ccb_tag;
+ ncb->ccb_otag = cb->ccb_otag;
+ cb->ccb_tag = SCSI_LOW_UNKTAG;
+ cb->ccb_otag = SCSI_LOW_UNKTAG;
+ if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
+ panic("%s: linked ccb retried\n", slp->sl_xname);
+
+ slp->sl_Qnexus = ncb;
+ slp->sl_ph_count = 0;
+
+ ncb->ccb_error = 0;
+ ncb->ccb_datalen = -1;
+ ncb->ccb_scp.scp_status = ST_UNKNOWN;
+ ncb->ccb_flags &= ~CCB_INTERNAL;
+
+ scsi_low_init_msgsys(slp, ti);
+
+ (*slp->sl_osdep_fp->scsi_low_osdep_ccb_setup) (slp, ncb);
+
+ if (ncb->ccb_tcmax < SCSI_LOW_MIN_TOUT)
+ ncb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
+ ncb->ccb_tc = ncb->ccb_tcmax;
+
+ /* setup saved scsi data pointer */
+ ncb->ccb_sscp = ncb->ccb_scp;
+ slp->sl_scp = ncb->ccb_sscp;
+ slp->sl_error = ncb->ccb_error;
+
+#ifdef SCSI_LOW_DIAGNOSTIC
+ scsi_low_msg_log_init(&ti->ti_log_msgin);
+ scsi_low_msg_log_init(&ti->ti_log_msgout);
+#endif /* SCSI_LOW_DIAGNOSTIC */
+ return EJUSTRETURN;
+}
+
+static int
+scsi_low_msginfunc_disc(slp)
+ struct scsi_low_softc *slp;
{
- struct scsi_low_softc *slp = ti->ti_sc;
SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC);
return 0;
}
static int
-scsi_low_msginfunc_sdp(ti)
- struct targ_info *ti;
+scsi_low_msginfunc_sdp(slp)
+ struct scsi_low_softc *slp;
{
- struct scsi_low_softc *slp = ti->ti_sc;
+ struct slccb *cb = slp->sl_Qnexus;
- if (ti->ti_nexus != NULL)
- ti->ti_nexus->ccb_sscp = slp->sl_scp;
+ if (cb != NULL)
+ {
+ cb->ccb_sscp.scp_datalen = slp->sl_scp.scp_datalen;
+ cb->ccb_sscp.scp_data = slp->sl_scp.scp_data;
+ }
else
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
+ scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
return 0;
}
static int
-scsi_low_msginfunc_rdp(ti)
- struct targ_info *ti;
+scsi_low_msginfunc_rp(slp)
+ struct scsi_low_softc *slp;
{
- struct scsi_low_softc *slp = ti->ti_sc;
- if (ti->ti_nexus != NULL)
- slp->sl_scp = ti->ti_nexus->ccb_sscp;
+ if (slp->sl_Qnexus != NULL)
+ slp->sl_scp = slp->sl_Qnexus->ccb_sscp;
else
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
+ scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_REJECT, 0);
return 0;
}
static int
-scsi_low_synch(ti)
- struct targ_info *ti;
+scsi_low_synch(slp)
+ struct scsi_low_softc *slp;
{
- struct scsi_low_softc *slp = ti->ti_sc;
-#ifdef SCSI_LOW_INFORM
- struct lun_info *li = ti->ti_li;
- u_int speed;
-#endif
- u_int period = 0, offset = 0;
+ struct targ_info *ti = slp->sl_Tnexus;
+ u_int period = 0, offset = 0, speed;
u_char *s;
int error;
- if (MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period &&
- MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset)
+ if ((MSGIN_PERIOD(ti) >= ti->ti_maxsynch.period &&
+ MSGIN_OFFSET(ti) <= ti->ti_maxsynch.offset) ||
+ MSGIN_OFFSET(ti) == 0)
{
if ((offset = MSGIN_OFFSET(ti)) != 0)
period = MSGIN_PERIOD(ti);
@@ -2128,28 +3898,137 @@ scsi_low_synch(ti)
return error;
}
-#ifdef SCSI_LOW_INFORM
+ ti->ti_osynch = ti->ti_maxsynch;
+ if (offset > 0)
+ {
+ ti->ti_setup_msg_done |= SCSI_LOW_MSG_SYNCH;
+ }
+
/* inform data */
- printf("%s(%d:%d): <%s> offset %d period %dns ",
- slp->sl_xname, ti->ti_id, li->li_lun, s, offset, period * 4);
- if (period != 0)
+ if ((slp->sl_show_result & SHOW_SYNCH_NEG) != 0)
{
- speed = 1000 * 10 / (period * 4);
- printf("%d.%d M/s", speed / 10, speed % 10);
+#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE
+ struct slccb *cb = slp->sl_Qnexus;
+
+ if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
+ return 0;
+#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
+
+ printf("%s(%d:*): <%s> offset %d period %dns ",
+ slp->sl_xname, ti->ti_id, s, offset, period * 4);
+
+ if (period != 0)
+ {
+ speed = 1000 * 10 / (period * 4);
+ printf("%d.%d M/s", speed / 10, speed % 10);
+ }
+ printf("\n");
}
- printf("\n");
-#endif
+ return 0;
+}
+
+static int
+scsi_low_wide(slp)
+ struct scsi_low_softc *slp;
+{
+ struct targ_info *ti = slp->sl_Tnexus;
+ int error;
+ ti->ti_width = MSGIN_WIDTHP(ti);
+ error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_WIDE);
+ if (error != 0)
+ {
+ /* XXX:
+ * Current width is not acceptable for our adapter.
+ * The adapter changes max width.
+ */
+ printf("%s: wide neg failed. retry wide msg neg ...\n",
+ slp->sl_xname);
+ return error;
+ }
+
+ ti->ti_owidth = ti->ti_width;
+ if (ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
+ {
+ ti->ti_setup_msg_done |=
+ (SCSI_LOW_MSG_SYNCH | SCSI_LOW_MSG_WIDE);
+ }
+
+ /* inform data */
+ if ((slp->sl_show_result & SHOW_WIDE_NEG) != 0)
+ {
+#ifdef SCSI_LOW_NEGOTIATE_BEFORE_SENSE
+ struct slccb *cb = slp->sl_Qnexus;
+
+ if (cb != NULL && (cb->ccb_flags & CCB_SENSE) != 0)
+ return 0;
+#endif /* SCSI_LOW_NEGOTIATE_BEFORE_SENSE */
+
+ printf("%s(%d:*): transfer width %d bits\n",
+ slp->sl_xname, ti->ti_id, 1 << (3 + ti->ti_width));
+ }
return 0;
}
static int
-scsi_low_msginfunc_ext(ti)
- struct targ_info *ti;
+scsi_low_msginfunc_simple_qtag(slp)
+ struct scsi_low_softc *slp;
{
- struct scsi_low_softc *slp = ti->ti_sc;
- struct slccb *cb = ti->ti_nexus;
- struct lun_info *li = ti->ti_li;
+ struct targ_info *ti = slp->sl_Tnexus;
+ scsi_low_tag_t etag = (scsi_low_tag_t) ti->ti_msgin[1];
+
+ if (slp->sl_Qnexus != NULL)
+ {
+ if (slp->sl_Qnexus->ccb_tag != etag)
+ {
+ slp->sl_error |= FATALIO;
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
+ SCSI_LOW_INFO(slp, ti, "MSGIN: qtag mismatch");
+ }
+ }
+ else if (scsi_low_establish_ccb(ti, slp->sl_Lnexus, etag) == NULL)
+ {
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id))
+ return 0;
+#endif /* SCSI_LOW_DEBUG */
+
+ slp->sl_error |= FATALIO;
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT_QTAG, 0);
+ SCSI_LOW_INFO(slp, ti, "MSGIN: taged ccb not found");
+ }
+ return 0;
+}
+
+static int
+scsi_low_msginfunc_i_wide_residue(slp)
+ struct scsi_low_softc *slp;
+{
+ struct targ_info *ti = slp->sl_Tnexus;
+ struct slccb *cb = slp->sl_Qnexus;
+ int res = (int) ti->ti_msgin[1];
+
+ if (cb == NULL || res <= 0 ||
+ (ti->ti_width == SCSI_LOW_BUS_WIDTH_16 && res > 1) ||
+ (ti->ti_width == SCSI_LOW_BUS_WIDTH_32 && res > 3))
+ return EINVAL;
+
+ if (slp->sl_scp.scp_datalen + res > cb->ccb_scp.scp_datalen)
+ return EINVAL;
+
+ slp->sl_scp.scp_datalen += res;
+ slp->sl_scp.scp_data -= res;
+ scsi_low_data_finish(slp);
+ return 0;
+}
+
+static int
+scsi_low_msginfunc_ext(slp)
+ struct scsi_low_softc *slp;
+{
+ struct slccb *cb = slp->sl_Qnexus;
+ struct lun_info *li = slp->sl_Lnexus;
+ struct targ_info *ti = slp->sl_Tnexus;
int count, retry;
u_int32_t *ptr;
@@ -2179,16 +4058,26 @@ scsi_low_msginfunc_ext(ti)
if (li == NULL)
break;
- retry = scsi_low_synch(ti);
+ retry = scsi_low_synch(slp);
if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0)
scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0);
+
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
+ {
+ scsi_low_test_atten(slp, ti, SCSI_LOW_MSG_SYNCH);
+ }
+#endif /* SCSI_LOW_DEBUG */
return 0;
case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE):
if (li == NULL)
break;
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0);
+ retry = scsi_low_wide(slp);
+ if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_WIDE) == 0)
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0);
+
return 0;
default:
@@ -2199,59 +4088,29 @@ scsi_low_msginfunc_ext(ti)
return EINVAL;
}
-static void
-scsi_low_retry_phase(ti)
- struct targ_info *ti;
-{
-
- switch (ti->ti_sphase)
- {
- case PH_MSGOUT:
- ti->ti_msgflags |= ti->ti_omsgflags;
- break;
-
- default:
- break;
- }
-}
-
static int
-scsi_low_msginfunc_parity(ti)
- struct targ_info *ti;
+scsi_low_msginfunc_parity(slp)
+ struct scsi_low_softc *slp;
{
- struct scsi_low_softc *slp = ti->ti_sc;
+ struct targ_info *ti = slp->sl_Tnexus;
- if (ti->ti_sphase != PH_MSGOUT)
- slp->sl_error |= PARITYERR;
- scsi_low_retry_phase(ti);
+ /* only I -> T, invalid! */
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0);
return 0;
}
static int
-scsi_low_msginfunc_msg_reject(ti)
- struct targ_info *ti;
+scsi_low_msginfunc_msg_reject(slp)
+ struct scsi_low_softc *slp;
{
- struct scsi_low_softc *slp = ti->ti_sc;
- struct lun_info *li = ti->ti_li;
+ struct targ_info *ti = slp->sl_Tnexus;
struct scsi_low_msgout_data *mdp;
u_int msgflags;
- if (li == NULL)
- {
- /* not yet lun nexus established! */
- goto out;
- }
-
- switch (ti->ti_sphase)
+ if (ti->ti_emsgflags != 0)
{
- case PH_CMD:
- slp->sl_error |= CMDREJECT;
- break;
-
- case PH_MSGOUT:
- if (ti->ti_emsgflags == 0)
- break;
-
+ printf("%s: msg flags [0x%x] rejected\n",
+ slp->sl_xname, ti->ti_emsgflags);
msgflags = SCSI_LOW_MSG_REJECT;
mdp = &scsi_low_msgout_data[0];
for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++)
@@ -2260,50 +4119,60 @@ scsi_low_msginfunc_msg_reject(ti)
{
ti->ti_emsgflags &= ~mdp->md_flags;
if (mdp->md_errfunc != NULL)
- (*mdp->md_errfunc) (ti, msgflags);
+ (*mdp->md_errfunc) (slp, msgflags);
break;
}
}
- break;
-
- default:
- break;
+ return 0;
}
-
-out:
- scsi_low_info(slp, ti, "msg rejected");
- slp->sl_error |= MSGERR;
- return 0;
+ else
+ {
+ SCSI_LOW_INFO(slp, ti, "MSGIN: rejected msg not found");
+ slp->sl_error |= MSGERR;
+ }
+ return EINVAL;
}
-void
+int
scsi_low_msgin(slp, ti, c)
struct scsi_low_softc *slp;
struct targ_info *ti;
- u_int8_t c;
+ u_int c;
{
struct scsi_low_msgin_data *sdp;
struct lun_info *li;
u_int8_t msg;
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if (ti != slp->sl_Tnexus)
+ {
+ scsi_low_print(slp, NULL);
+ panic("scsi_low_msgin: Target nexus inconsistent");
+ }
+#endif /* SCSI_LOW_DIAGNOSTIC */
+
/*
* Phase changes, clear the pointer.
*/
if (ti->ti_ophase != ti->ti_phase)
{
- ti->ti_sphase = ti->ti_ophase;
- ti->ti_ophase = ti->ti_phase;
MSGINPTR_CLR(ti);
-#ifdef SCSI_LOW_DIAGNOSTIC
- ti->ti_msgin_hist_pointer = 0;
-#endif /* SCSI_LOW_DIAGNOSTIC */
+ ti->ti_msgin_parity_error = 0;
+
+ slp->sl_ph_count ++;
+ if (slp->sl_ph_count > SCSI_LOW_MAX_PHCHANGES)
+ {
+ printf("%s: too many phase changes\n", slp->sl_xname);
+ slp->sl_error |= FATALIO;
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
+ }
}
/*
* Store a current messages byte into buffer and
* wait for the completion of the current msg.
*/
- ti->ti_msgin[ti->ti_msginptr ++] = c;
+ ti->ti_msgin[ti->ti_msginptr ++] = (u_int8_t) c;
if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN)
{
ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1;
@@ -2311,6 +4180,19 @@ scsi_low_msgin(slp, ti, c)
}
/*
+ * Check parity errors.
+ */
+ if ((c & SCSI_LOW_DATA_PE) != 0)
+ {
+ ti->ti_msgin_parity_error ++;
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
+ goto out;
+ }
+
+ if (ti->ti_msgin_parity_error != 0)
+ goto out;
+
+ /*
* Calculate messages length.
*/
msg = ti->ti_msgin[0];
@@ -2322,188 +4204,645 @@ scsi_low_msgin(slp, ti, c)
if (ti->ti_msginlen == 0)
{
ti->ti_msginlen = sdp->md_len;
-#ifdef SCSI_LOW_DIAGNOSTIC
- if (ti->ti_msgin_hist_pointer < MSGIN_HISTORY_LEN)
- {
- ti->ti_msgin_history[ti->ti_msgin_hist_pointer] = msg;
- ti->ti_msgin_hist_pointer ++;
- }
-#endif /* SCSI_LOW_DIAGNOSTIC */
}
/*
* Check comletion.
*/
if (ti->ti_msginptr < ti->ti_msginlen)
- return;
+ return EJUSTRETURN;
/*
* Do process.
*/
if ((msg & MSG_IDENTIFY) == 0)
{
- (void) ((*sdp->md_msgfunc) (ti));
+ if (((*sdp->md_msgfunc) (slp)) == EJUSTRETURN)
+ return EJUSTRETURN;
}
else
{
- li = ti->ti_li;
+ li = slp->sl_Lnexus;
if (li == NULL)
{
- li = scsi_low_establish_lun(ti, MSGCMD_LUN(msg));
+ li = scsi_low_alloc_li(ti, MSGCMD_LUN(msg), 0);
if (li == NULL)
goto badlun;
+ slp->sl_Lnexus = li;
+ (*slp->sl_funcs->scsi_low_establish_lun_nexus) (slp);
}
+ else
+ {
+ if (MSGCMD_LUN(msg) != li->li_lun)
+ goto badlun;
+ }
- if (ti->ti_nexus == NULL)
+ if (slp->sl_Qnexus == NULL && li->li_nqio == 0)
{
- /* XXX:
- * move the following functions to
- * tag queue msg process in the future.
- */
if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG))
+ {
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_NEXUS_CHECK, ti->ti_id) != 0)
+ {
+ goto out;
+ }
+#endif /* SCSI_LOW_DEBUG */
goto badlun;
+ }
}
-
- if (MSGCMD_LUN(msg) != li->li_lun)
- goto badlun;
}
+ goto out;
/*
- * Msg process completed, reset msin pointer and assert ATN if desired.
+ * Msg process completed, reset msgin pointer and assert ATN if desired.
*/
- if (ti->ti_msginptr >= ti->ti_msginlen)
+badlun:
+ slp->sl_error |= FATALIO;
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
+ SCSI_LOW_INFO(slp, ti, "MSGIN: identify wrong");
+
+out:
+ if (ti->ti_msginptr < ti->ti_msginlen)
+ return EJUSTRETURN;
+
+#ifdef SCSI_LOW_DIAGNOSTIC
+ scsi_low_msg_log_write(&ti->ti_log_msgin,
+ &ti->ti_msgin[0], ti->ti_msginlen);
+#endif /* SCSI_LOW_DIAGNOSTIC */
+
+ MSGINPTR_CLR(ti);
+ return 0;
+}
+
+/**********************************************************
+ * disconnect
+ **********************************************************/
+int
+scsi_low_disconnected(slp, ti)
+ struct scsi_low_softc *slp;
+ struct targ_info *ti;
+{
+ struct slccb *cb = slp->sl_Qnexus;
+
+ /* check phase completion */
+ switch (slp->sl_msgphase)
{
- ti->ti_sphase = ti->ti_phase;
- MSGINPTR_CLR(ti);
+ case MSGPH_RESET:
+ scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
+ scsi_low_msginfunc_cc(slp);
+ scsi_low_reset_nexus_target(slp, slp->sl_Tnexus, 0);
+ goto io_resume;
+
+ case MSGPH_ABORT:
+ scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
+ scsi_low_msginfunc_cc(slp);
+ scsi_low_reset_nexus_lun(slp, slp->sl_Lnexus, 0);
+ goto io_resume;
+
+ case MSGPH_TERM:
+ scsi_low_statusin(slp, slp->sl_Tnexus, ST_GOOD);
+ scsi_low_msginfunc_cc(slp);
+ goto io_resume;
- if (scsi_low_is_msgout_continue(ti) != 0)
+ case MSGPH_DISC:
+ if (cb != NULL)
{
+ struct lun_info *li;
+
+ li = cb->li;
+ TAILQ_INSERT_TAIL(&li->li_discq, cb, ccb_chain);
+ cb->ccb_flags |= CCB_DISCQ;
+ cb->ccb_error |= slp->sl_error;
+ li->li_disc ++;
+ ti->ti_disc ++;
+ slp->sl_disc ++;
+ }
+
+#ifdef SCSI_LOW_STATICS
+ scsi_low_statics.nexus_disconnected ++;
+#endif /* SCSI_LOW_STATICS */
+
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_DISC, ti->ti_id) != 0)
+ {
+ printf("## SCSI_LOW_DISCONNECTED ===============\n");
+ scsi_low_print(slp, NULL);
+ }
+#endif /* SCSI_LOW_DEBUG */
+ break;
+
+ case MSGPH_NULL:
+ slp->sl_error |= FATALIO;
+ if (ti->ti_phase == PH_SELSTART)
+ slp->sl_error |= SELTIMEOUTIO;
+ else
+ slp->sl_error |= UBFERR;
+ /* fall through */
+
+ case MSGPH_LCTERM:
+ case MSGPH_CMDC:
+io_resume:
+ if (cb == NULL)
+ break;
+
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_TEST_GO(SCSI_LOW_ATTEN_CHECK, ti->ti_id))
+ {
+ if (cb->ccb_omsgoutflag == SCSI_LOW_MSG_NOOP &&
+ (cb->ccb_msgoutflag != 0 ||
+ (ti->ti_msgflags & SCSI_LOW_MSG_NOOP)))
+ {
+ scsi_low_info(slp, ti, "ATTEN CHECK FAILED");
+ }
+ }
+#endif /* SCSI_LOW_DEBUG */
+
+ cb->ccb_error |= slp->sl_error;
+ if (scsi_low_done(slp, cb) == SCSI_LOW_DONE_RETRY)
+ {
+ cb->ccb_flags |= CCB_STARTQ;
+ TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain);
+ }
+ break;
+ }
+
+ scsi_low_bus_release(slp, ti);
+ scsi_low_start(slp);
+ return 1;
+}
+
+/**********************************************************
+ * TAG operations
+ **********************************************************/
+int
+scsi_low_alloc_qtag(cb)
+ struct slccb *cb;
+{
+ struct lun_info *li = cb->li;
+ scsi_low_tag_t etag;
+
+ if (cb->ccb_otag != SCSI_LOW_UNKTAG)
+ return 0;
+
+#ifndef SCSI_LOW_ALT_QTAG_ALLOCATE
+ etag = ffs(li->li_qtagbits);
+ if (etag == 0)
+ return ENOSPC;
+
+ li->li_qtagbits &= ~(1 << (etag - 1));
+ cb->ccb_otag = etag;
+ return 0;
+
+#else /* SCSI_LOW_ALT_QTAG_ALLOCATE */
+ for (etag = li->li_qd ; li->li_qd < SCSI_LOW_MAXNEXUS; li->li_qd ++)
+ if (li->li_qtagarray[li->li_qd] == 0)
+ goto found;
+
+ for (li->li_qd = 0; li->li_qd < etag; li->li_qd ++)
+ if (li->li_qtagarray[li->li_qd] == 0)
+ goto found;
+
+ return ENOSPC;
+
+found:
+ li->li_qtagarray[li->li_qd] ++;
+ cb->ccb_otag = (li->li_qd ++);
+ return 0;
+#endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */
+}
+
+int
+scsi_low_dealloc_qtag(cb)
+ struct slccb *cb;
+{
+ struct lun_info *li = cb->li;
+ scsi_low_tag_t etag;
+
+ if (cb->ccb_otag == SCSI_LOW_UNKTAG)
+ return 0;
+
+#ifndef SCSI_LOW_ALT_QTAG_ALLOCATE
+ etag = cb->ccb_otag - 1;
#ifdef SCSI_LOW_DIAGNOSTIC
- printf("SCSI_LOW_ATTETION(msgin): 0x%x\n",
- ti->ti_msgflags);
+ if (etag >= sizeof(li->li_qtagbits) * NBBY)
+ panic("scsi_low_dealloc_tag: illegal tag");
#endif /* SCSI_LOW_DIAGNOSTIC */
- scsi_low_attention(slp, ti);
- }
+ li->li_qtagbits |= (1 << etag);
+
+#else /* SCSI_LOW_ALT_QTAG_ALLOCATE */
+ etag = cb->ccb_otag;
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if (etag >= SCSI_LOW_MAXNEXUS)
+ panic("scsi_low_dealloc_tag: illegal tag");
+#endif /* SCSI_LOW_DIAGNOSTIC */
+ li->li_qtagarray[etag] --;
+#endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */
+
+ cb->ccb_otag = SCSI_LOW_UNKTAG;
+ return 0;
+}
+
+struct slccb *
+scsi_low_revoke_ccb(slp, cb, fdone)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+ int fdone;
+{
+ struct targ_info *ti = cb->ti;
+ struct lun_info *li = cb->li;
+
+#ifdef SCSI_LOW_DIAGNOSTIC
+ if ((cb->ccb_flags & (CCB_STARTQ | CCB_DISCQ)) ==
+ (CCB_STARTQ | CCB_DISCQ))
+ {
+ panic("%s: ccb in both queue\n", slp->sl_xname);
}
- return;
+#endif /* SCSI_LOW_DIAGNOSTIC */
-badlun:
- scsi_low_info(slp, ti, "MSGIN: identify lun mismatch");
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0);
+ if ((cb->ccb_flags & CCB_STARTQ) != 0)
+ {
+ TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain);
+ }
+
+ if ((cb->ccb_flags & CCB_DISCQ) != 0)
+ {
+ TAILQ_REMOVE(&li->li_discq, cb, ccb_chain);
+ li->li_disc --;
+ ti->ti_disc --;
+ slp->sl_disc --;
+ }
+
+ cb->ccb_flags &= ~(CCB_STARTQ | CCB_DISCQ |
+ CCB_SENSE | CCB_CLEARQ | CCB_INTERNAL);
+
+ if (fdone != 0 &&
+ (cb->ccb_rcnt ++ >= slp->sl_max_retry ||
+ (cb->ccb_flags & CCB_NORETRY) != 0))
+ {
+ cb->ccb_error |= FATALIO;
+ cb->ccb_flags &= ~CCB_AUTOSENSE;
+ if (scsi_low_done(slp, cb) != SCSI_LOW_DONE_COMPLETE)
+ panic("%s: done ccb retried\n", slp->sl_xname);
+ return NULL;
+ }
+ else
+ {
+ cb->ccb_error |= PENDINGIO;
+ scsi_low_deactivate_qtag(cb);
+ scsi_low_ccb_message_retry(cb);
+ cb->ccb_tc = cb->ccb_tcmax = SCSI_LOW_MIN_TOUT;
+ return cb;
+ }
}
+void
+scsi_low_reset_nexus_lun(slp, li, fdone)
+ struct scsi_low_softc *slp;
+ struct lun_info *li;
+ int fdone;
+{
+ struct slccb *cb, *ncb, *ecb;
+
+ if (li == NULL)
+ return;
+
+ ecb = NULL;
+ for (cb = TAILQ_FIRST(&li->li_discq); cb != NULL; cb = ncb)
+ {
+ ncb = TAILQ_NEXT(cb, ccb_chain);
+ cb = scsi_low_revoke_ccb(slp, cb, fdone);
+ if (cb != NULL)
+ {
+ /*
+ * presumely keep ordering of io
+ */
+ cb->ccb_flags |= CCB_STARTQ;
+ if (ecb == NULL)
+ {
+ TAILQ_INSERT_HEAD(&slp->sl_start,\
+ cb, ccb_chain);
+ }
+ else
+ {
+ TAILQ_INSERT_AFTER(&slp->sl_start,\
+ ecb, cb, ccb_chain);
+ }
+ ecb = cb;
+ }
+ }
+}
+
/**************************************************************
* Qurik setup
**************************************************************/
-#define MAXOFFSET 0x10
-
static void
-scsi_low_calcf(ti, li)
- struct targ_info *ti;
+scsi_low_calcf_lun(li)
struct lun_info *li;
{
- u_int period;
- u_int8_t offset;
+ struct targ_info *ti = li->li_ti;
struct scsi_low_softc *slp = ti->ti_sc;
+ u_int cfgflags, diskflags;
+
+ if (li->li_flags_valid == SCSI_LOW_LUN_FLAGS_ALL_VALID)
+ cfgflags = li->li_cfgflags;
+ else
+ cfgflags = 0;
+
+ diskflags = li->li_diskflags & li->li_quirks;
+ /* disconnect */
li->li_flags &= ~SCSI_LOW_DISC;
if ((slp->sl_cfgflags & CFG_NODISC) == 0 &&
-#ifdef SDEV_NODISC
- (li->li_quirks & SDEV_NODISC) == 0 &&
-#endif /* SDEV_NODISC */
- (li->li_cfgflags & SCSI_LOW_DISC) != 0)
+ (diskflags & SCSI_LOW_DISK_DISC) != 0 &&
+ (cfgflags & SCSI_LOW_DISC) != 0)
li->li_flags |= SCSI_LOW_DISC;
+ /* parity */
li->li_flags |= SCSI_LOW_NOPARITY;
if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 &&
-#ifdef SDEV_NOPARITY
- (li->li_quirks & SDEV_NOPARITY) == 0 &&
-#endif /* SDEV_NOPARITY */
- (li->li_cfgflags & SCSI_LOW_NOPARITY) == 0)
+ (diskflags & SCSI_LOW_DISK_PARITY) != 0 &&
+ (cfgflags & SCSI_LOW_NOPARITY) == 0)
li->li_flags &= ~SCSI_LOW_NOPARITY;
- li->li_flags &= ~SCSI_LOW_SYNC;
- if ((li->li_cfgflags & SCSI_LOW_SYNC) &&
- (slp->sl_cfgflags & CFG_ASYNC) == 0)
+ /* qtag */
+ if ((slp->sl_cfgflags & CFG_NOQTAG) == 0 &&
+ (cfgflags & SCSI_LOW_QTAG) != 0 &&
+ (diskflags & SCSI_LOW_DISK_QTAG) != 0)
{
- offset = SCSI_LOW_OFFSET(li->li_cfgflags);
- if (offset > ti->ti_maxsynch.offset)
- offset = ti->ti_maxsynch.offset;
- li->li_flags |= SCSI_LOW_SYNC;
+ li->li_flags |= SCSI_LOW_QTAG;
+ li->li_maxnexus = SCSI_LOW_MAXNEXUS;
+ li->li_maxnqio = li->li_maxnexus;
}
else
- offset = 0;
-
- if (offset > 0)
{
- period = SCSI_LOW_PERIOD(li->li_cfgflags);
- if (period > SCSI_LOW_MAX_SYNCH_SPEED)
- period = SCSI_LOW_MAX_SYNCH_SPEED;
- if (period != 0)
- period = 1000 * 10 / (period * 4);
- if (period < ti->ti_maxsynch.period)
- period = ti->ti_maxsynch.period;
+ li->li_flags &= ~SCSI_LOW_QTAG;
+ li->li_maxnexus = 0;
+ li->li_maxnqio = li->li_maxnexus;
}
- else
- period = 0;
+ /* cmd link */
+ li->li_flags &= ~SCSI_LOW_LINK;
+ if ((cfgflags & SCSI_LOW_LINK) != 0 &&
+ (diskflags & SCSI_LOW_DISK_LINK) != 0)
+ li->li_flags |= SCSI_LOW_LINK;
+
+ /* compatible flags */
+ li->li_flags &= ~SCSI_LOW_SYNC;
+ if (ti->ti_maxsynch.offset > 0)
+ li->li_flags |= SCSI_LOW_SYNC;
+
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
+ {
+ scsi_low_calcf_show(li);
+ }
+#endif /* SCSI_LOW_DEBUG */
+}
+
+static void
+scsi_low_calcf_target(ti)
+ struct targ_info *ti;
+{
+ struct scsi_low_softc *slp = ti->ti_sc;
+ u_int offset, period, diskflags;
+
+ diskflags = ti->ti_diskflags & ti->ti_quirks;
+
+ /* synch */
+ if ((slp->sl_cfgflags & CFG_ASYNC) == 0 &&
+ (diskflags & SCSI_LOW_DISK_SYNC) != 0)
+ {
+ offset = ti->ti_maxsynch.offset;
+ period = ti->ti_maxsynch.period;
+ if (offset == 0 || period == 0)
+ offset = period = 0;
+ }
+ else
+ {
+ offset = period = 0;
+ }
+
ti->ti_maxsynch.offset = offset;
ti->ti_maxsynch.period = period;
+
+ /* wide */
+ if ((diskflags & SCSI_LOW_DISK_WIDE_32) == 0 &&
+ ti->ti_width > SCSI_LOW_BUS_WIDTH_16)
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_16;
+
+ if ((diskflags & SCSI_LOW_DISK_WIDE_16) == 0 &&
+ ti->ti_width > SCSI_LOW_BUS_WIDTH_8)
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
+
+ if (ti->ti_flags_valid == SCSI_LOW_TARG_FLAGS_ALL_VALID)
+ {
+ if (ti->ti_maxsynch.offset != ti->ti_osynch.offset ||
+ ti->ti_maxsynch.period != ti->ti_osynch.period)
+ ti->ti_setup_msg |= SCSI_LOW_MSG_SYNCH;
+ if (ti->ti_width != ti->ti_owidth)
+ ti->ti_setup_msg |= (SCSI_LOW_MSG_WIDE | SCSI_LOW_MSG_SYNCH);
+
+ ti->ti_osynch = ti->ti_maxsynch;
+ ti->ti_owidth = ti->ti_width;
+ }
+
+#ifdef SCSI_LOW_DEBUG
+ if (SCSI_LOW_DEBUG_GO(SCSI_LOW_DEBUG_CALCF, ti->ti_id) != 0)
+ {
+ printf("%s(%d:*): max period(%dns) offset(%d) width(%d)\n",
+ slp->sl_xname, ti->ti_id,
+ ti->ti_maxsynch.period * 4,
+ ti->ti_maxsynch.offset,
+ ti->ti_width);
+ }
+#endif /* SCSI_LOW_DEBUG */
}
-#ifdef SCSI_LOW_TARGET_OPEN
-static int
-scsi_low_target_open(link, cf)
- struct scsipi_link *link;
- struct cfdata *cf;
+static void
+scsi_low_calcf_show(li)
+ struct lun_info *li;
{
- u_int target = link->scsipi_scsi.target;
- u_int lun = link->scsipi_scsi.lun;
+ struct targ_info *ti = li->li_ti;
+ struct scsi_low_softc *slp = ti->ti_sc;
+
+ printf("%s(%d:%d): period(%d ns) offset(%d) width(%d) flags 0x%b\n",
+ slp->sl_xname, ti->ti_id, li->li_lun,
+ ti->ti_maxsynch.period * 4,
+ ti->ti_maxsynch.offset,
+ ti->ti_width,
+ li->li_flags, SCSI_LOW_BITS);
+}
+
+#ifdef SCSI_LOW_START_UP_CHECK
+/**************************************************************
+ * scsi world start up
+ **************************************************************/
+static int scsi_low_poll __P((struct scsi_low_softc *, struct slccb *));
+
+static int
+scsi_low_start_up(slp)
struct scsi_low_softc *slp;
+{
struct targ_info *ti;
struct lun_info *li;
+ struct slccb *cb;
+ int target, lun;
- slp = (struct scsi_low_softc *) link->adapter_softc;
- ti = slp->sl_ti[target];
- li = scsi_low_alloc_li(ti, lun, 0);
- if (li == NULL)
- return 0;
+ printf("%s: scsi_low: probing all devices ....\n", slp->sl_xname);
- li->li_quirks = (u_int) link->quirks;
- li->li_cfgflags = cf->cf_flags;
- if (li->li_state > UNIT_SYNCH)
- li->li_state = UNIT_SYNCH;
+ for (target = 0; target < slp->sl_ntargs; target ++)
+ {
+ if (target == slp->sl_hostid)
+ {
+ if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
+ {
+ printf("%s: scsi_low: target %d (host card)\n",
+ slp->sl_xname, target);
+ }
+ continue;
+ }
- scsi_low_calcf(ti, li);
+ if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
+ {
+ printf("%s: scsi_low: target %d lun ",
+ slp->sl_xname, target);
+ }
- printf("%s(%d:%d): max period(%dns) max offset(%d) flags 0x%b\n",
- slp->sl_xname, target, lun,
- ti->ti_maxsynch.period * 4,
- ti->ti_maxsynch.offset,
- li->li_flags, SCSI_LOW_BITS);
+ ti = slp->sl_ti[target];
+ for (lun = 0; lun < slp->sl_nluns; lun ++)
+ {
+ if ((cb = SCSI_LOW_ALLOC_CCB(1)) == NULL)
+ break;
+
+ cb->osdep = NULL;
+ cb->bp = NULL;
+
+ li = scsi_low_alloc_li(ti, lun, 1);
+
+ scsi_low_enqueue(slp, ti, li, cb,
+ CCB_AUTOSENSE | CCB_POLLED, 0);
+
+ scsi_low_poll(slp, cb);
+
+ if (li->li_state != SCSI_LOW_LUN_OK)
+ break;
+
+ if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
+ {
+ printf("%d ", lun);
+ }
+ }
+
+ if ((slp->sl_show_result & SHOW_PROBE_RES) != 0)
+ {
+ printf("\n");
+ }
+ }
return 0;
}
-#endif /* SCSI_LOW_TARGET_OPEN */
+
+static int
+scsi_low_poll(slp, cb)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+{
+ int tcount;
+
+ tcount = 0;
+ while (slp->sl_nio > 0)
+ {
+ SCSI_LOW_DELAY((1000 * 1000) / SCSI_LOW_POLL_HZ);
+
+ (*slp->sl_funcs->scsi_low_poll) (slp);
+ if (tcount ++ < SCSI_LOW_POLL_HZ / SCSI_LOW_TIMEOUT_HZ)
+ continue;
+
+ tcount = 0;
+ scsi_low_timeout_check(slp);
+ }
+
+ return 0;
+}
+#endif /* SCSI_LOW_START_UP_CHECK */
/**********************************************************
* DEBUG SECTION
**********************************************************/
+#ifdef SCSI_LOW_DEBUG
+static void
+scsi_low_test_abort(slp, ti, li)
+ struct scsi_low_softc *slp;
+ struct targ_info *ti;
+ struct lun_info *li;
+{
+ struct slccb *acb;
+
+ if (li->li_disc > 1)
+ {
+ acb = TAILQ_FIRST(&li->li_discq);
+ if (scsi_low_abort_ccb(slp, acb) == 0)
+ {
+ printf("%s: aborting ccb(0x%lx) start\n",
+ slp->sl_xname, (u_long) acb);
+ }
+ }
+}
+
+static void
+scsi_low_test_atten(slp, ti, msg)
+ struct scsi_low_softc *slp;
+ struct targ_info *ti;
+ u_int msg;
+{
+
+ if (slp->sl_ph_count < SCSI_LOW_MAX_ATTEN_CHECK)
+ scsi_low_assert_msg(slp, ti, msg, 0);
+ else
+ printf("%s: atten check OK\n", slp->sl_xname);
+}
+
static void
+scsi_low_test_cmdlnk(slp, cb)
+ struct scsi_low_softc *slp;
+ struct slccb *cb;
+{
+#define SCSI_LOW_CMDLNK_NOK (CCB_INTERNAL | CCB_SENSE | CCB_CLEARQ)
+
+ if ((cb->ccb_flags & SCSI_LOW_CMDLNK_NOK) != 0)
+ return;
+
+ memcpy(cb->ccb_scsi_cmd, slp->sl_scp.scp_cmd,
+ slp->sl_scp.scp_cmdlen);
+ cb->ccb_scsi_cmd[slp->sl_scp.scp_cmdlen - 1] |= 1;
+ slp->sl_scp.scp_cmd = cb->ccb_scsi_cmd;
+}
+#endif /* SCSI_LOW_DEBUG */
+
+/* static */ void
scsi_low_info(slp, ti, s)
struct scsi_low_softc *slp;
struct targ_info *ti;
u_char *s;
{
- printf("%s: SCSI_LOW: %s\n", slp->sl_xname, s);
+ if (slp == NULL)
+ slp = LIST_FIRST(&sl_tab);
+ if (s == NULL)
+ s = "no message";
+
+ printf(">>>>> SCSI_LOW_INFO(0x%lx): %s\n", (u_long) slp->sl_Tnexus, s);
if (ti == NULL)
{
- TAILQ_FOREACH(ti, &slp->sl_titab, ti_chain)
+ for (ti = TAILQ_FIRST(&slp->sl_titab); ti != NULL;
+ ti = TAILQ_NEXT(ti, ti_chain))
+ {
scsi_low_print(slp, ti);
+ }
}
else
+ {
scsi_low_print(slp, ti);
-
+ }
}
static u_char *phase[] =
@@ -2517,76 +4856,87 @@ scsi_low_print(slp, ti)
struct scsi_low_softc *slp;
struct targ_info *ti;
{
- struct slccb *cb = NULL;
+ struct lun_info *li;
+ struct slccb *cb;
+ struct sc_p *sp;
- if (ti == NULL)
- ti = slp->sl_nexus;
- if (ti != NULL)
- cb = ti->ti_nexus;
+ if (ti == NULL || ti == slp->sl_Tnexus)
+ {
+ ti = slp->sl_Tnexus;
+ li = slp->sl_Lnexus;
+ cb = slp->sl_Qnexus;
+ }
+ else
+ {
+ li = LIST_FIRST(&ti->ti_litab);
+ cb = TAILQ_FIRST(&li->li_discq);
+ }
+ sp = &slp->sl_scp;
- printf("%s: TARGET(0x%lx) T_NEXUS(0x%lx) C_NEXUS(0x%lx) NDISCS(%d)\n",
- slp->sl_xname, (u_long) ti, (u_long) slp->sl_nexus,
- (u_long) cb, slp->sl_disc);
+ printf("%s: === NEXUS T(0x%lx) L(0x%lx) Q(0x%lx) NIO(%d) ===\n",
+ slp->sl_xname, (u_long) ti, (u_long) li, (u_long) cb,
+ slp->sl_nio);
/* target stat */
if (ti != NULL)
{
- struct sc_p *sp = &slp->sl_scp;
- struct lun_info *li = ti->ti_li;
- u_int flags = 0;
+ u_int flags = 0, maxnqio = 0, nqio = 0;
int lun = -1;
if (li != NULL)
{
lun = li->li_lun;
flags = li->li_flags;
+ maxnqio = li->li_maxnqio;
+ nqio = li->li_nqio;
}
- printf("%s(%d:%d) ph<%s> => ph<%s>\n", slp->sl_xname,
+ printf("%s(%d:%d) ph<%s> => ph<%s> DISC(%d) QIO(%d:%d)\n",
+ slp->sl_xname,
ti->ti_id, lun, phase[(int) ti->ti_ophase],
- phase[(int) ti->ti_phase]);
-
-printf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] STATUSIN: 0x%x T_FLAGS: 0x%x\n",
- (u_int) (ti->ti_msginptr),
- (u_int) (ti->ti_msgin[0]),
- (u_int) (ti->ti_msgin[1]),
- (u_int) (ti->ti_msgin[2]),
- (u_int) (ti->ti_msgin[3]),
- (u_int) (ti->ti_msgin[4]),
- ti->ti_status, ti->ti_tflags);
-#ifdef SCSI_LOW_DIAGNOSTIC
-printf("MSGIN HISTORY: (%d) [0x%x] => [0x%x] => [0x%x] => [0x%x] => [0x%x]\n",
- ti->ti_msgin_hist_pointer,
- (u_int) (ti->ti_msgin_history[0]),
- (u_int) (ti->ti_msgin_history[1]),
- (u_int) (ti->ti_msgin_history[2]),
- (u_int) (ti->ti_msgin_history[3]),
- (u_int) (ti->ti_msgin_history[4]));
-#endif /* SCSI_LOW_DIAGNOSTIC */
-
-printf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n",
- (u_int) ti->ti_msgflags,
- (u_int) (ti->ti_msgoutstr[0]),
- (u_int) (ti->ti_msgoutstr[1]),
- (u_int) (ti->ti_msgoutstr[2]),
- (u_int) (ti->ti_msgoutstr[3]),
- (u_int) (ti->ti_msgoutstr[4]),
- ti->ti_msgoutlen,
- flags, SCSI_LOW_BITS);
-
-printf("SCP: datalen 0x%x dataaddr 0x%lx ",
- sp->scp_datalen,
- (u_long) sp->scp_data);
+ phase[(int) ti->ti_phase], ti->ti_disc,
+ nqio, maxnqio);
if (cb != NULL)
{
-printf("CCB: cmdlen %x cmdaddr %lx cmd[0] %x datalen %x",
- cb->ccb_scp.scp_cmdlen,
- (u_long) cb->ccb_scp.scp_cmd,
+printf("CCB: cmd[0] 0x%x clen 0x%x dlen 0x%x<0x%x stat 0x%x err %b\n",
(u_int) cb->ccb_scp.scp_cmd[0],
- cb->ccb_scp.scp_datalen);
+ cb->ccb_scp.scp_cmdlen,
+ cb->ccb_datalen,
+ cb->ccb_scp.scp_datalen,
+ (u_int) cb->ccb_sscp.scp_status,
+ cb->ccb_error, SCSI_LOW_ERRORBITS);
}
- printf("\n");
+
+printf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] attention: %d\n",
+ (u_int) (ti->ti_msginptr),
+ (u_int) (ti->ti_msgin[0]),
+ (u_int) (ti->ti_msgin[1]),
+ (u_int) (ti->ti_msgin[2]),
+ (u_int) (ti->ti_msgin[3]),
+ (u_int) (ti->ti_msgin[4]),
+ slp->sl_atten);
+
+printf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n",
+ (u_int) ti->ti_msgflags,
+ (u_int) (ti->ti_msgoutstr[0]),
+ (u_int) (ti->ti_msgoutstr[1]),
+ (u_int) (ti->ti_msgoutstr[2]),
+ (u_int) (ti->ti_msgoutstr[3]),
+ (u_int) (ti->ti_msgoutstr[4]),
+ ti->ti_msgoutlen,
+ flags, SCSI_LOW_BITS);
+
+#ifdef SCSI_LOW_DIAGNOSTIC
+ scsi_low_msg_log_show(&ti->ti_log_msgin, "MIN LOG ", 2);
+ scsi_low_msg_log_show(&ti->ti_log_msgout, "MOUT LOG", 2);
+#endif /* SCSI_LOW_DIAGNOSTIC */
+
}
- printf("error flags %b\n", slp->sl_error, SCSI_LOW_ERRORBITS);
+
+ printf("SCB: daddr 0x%lx dlen 0x%x stat 0x%x err %b\n",
+ (u_long) sp->scp_data,
+ sp->scp_datalen,
+ (u_int) sp->scp_status,
+ slp->sl_error, SCSI_LOW_ERRORBITS);
}
OpenPOWER on IntegriCloud