summaryrefslogtreecommitdiffstats
path: root/sys
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
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')
-rw-r--r--sys/cam/scsi/scsi_low.c4992
-rw-r--r--sys/cam/scsi/scsi_low.h678
-rw-r--r--sys/cam/scsi/scsi_low_pisa.c129
-rw-r--r--sys/cam/scsi/scsi_low_pisa.h21
-rw-r--r--sys/conf/options.pc984
-rw-r--r--sys/dev/ct/bshw_machdep.c396
-rw-r--r--sys/dev/ct/bshwvar.h32
-rw-r--r--sys/dev/ct/ct.c809
-rw-r--r--sys/dev/ct/ct_isa.c114
-rw-r--r--sys/dev/ct/ct_machdep.h149
-rw-r--r--sys/dev/ct/ctvar.h70
-rw-r--r--sys/dev/ncv/ncr53c500.c673
-rw-r--r--sys/dev/ncv/ncr53c500_pccard.c8
-rw-r--r--sys/dev/ncv/ncr53c500hw.h22
-rw-r--r--sys/dev/ncv/ncr53c500hwtab.h20
-rw-r--r--sys/dev/ncv/ncr53c500reg.h7
-rw-r--r--sys/dev/ncv/ncr53c500var.h40
-rw-r--r--sys/dev/nsp/nsp.c1326
-rw-r--r--sys/dev/nsp/nsp_pccard.c8
-rw-r--r--sys/dev/nsp/nspreg.h22
-rw-r--r--sys/dev/nsp/nspvar.h54
-rw-r--r--sys/dev/stg/tmc18c30.c995
-rw-r--r--sys/dev/stg/tmc18c30_isa.c9
-rw-r--r--sys/dev/stg/tmc18c30_pccard.c9
-rw-r--r--sys/dev/stg/tmc18c30reg.h15
-rw-r--r--sys/dev/stg/tmc18c30var.h48
26 files changed, 7499 insertions, 3151 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);
}
diff --git a/sys/cam/scsi/scsi_low.h b/sys/cam/scsi/scsi_low.h
index b569dd7..fb377c8 100644
--- a/sys/cam/scsi/scsi_low.h
+++ b/sys/cam/scsi/scsi_low.h
@@ -1,15 +1,21 @@
/* $FreeBSD$ */
-/* $NecBSD: scsi_low.h,v 1.24 1999/07/23 21:00:05 honda Exp $ */
+/* $NecBSD: scsi_low.h,v 1.24.10.5 2001/06/26 07:31:46 honda Exp $ */
/* $NetBSD$ */
#define SCSI_LOW_DIAGNOSTIC
+#define SCSI_LOW_ALT_QTAG_ALLOCATE
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1995, 1996, 1997, 1998
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
- * Copyright (c) 1995, 1996, 1997, 1998
+ * 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
@@ -38,12 +44,28 @@
#ifndef _SCSI_LOW_H_
#define _SCSI_LOW_H_
-#ifdef __NetBSD__
+/*================================================
+ * Scsi low OSDEP
+ * (All os depend structures should be here!)
+ ================================================*/
+/******** interface ******************************/
+#ifdef __NetBSD__
+#define SCSI_LOW_INTERFACE_XS
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+#define SCSI_LOW_INTERFACE_CAM
+#define CAM
+#endif /* __FreeBSD__ */
+
+/******** includes *******************************/
+#ifdef __NetBSD__
#include <i386/Cbus/dev/scsi_dvcfg.h>
-#endif
-#ifdef __FreeBSD__
+#include <dev/isa/ccbque.h>
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
#include <sys/device_port.h>
-#define CAM
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
@@ -51,9 +73,99 @@
#include <cam/cam_debug.h>
#include <cam/scsi/scsi_dvcfg.h>
+#include <i386/isa/ccbque.h>
+#endif /* __FreeBSD__ */
+
+/******** functions macro ************************/
+#ifdef __NetBSD__
+#define SCSI_LOW_DEBUGGER(dev) Debugger()
+#define SCSI_LOW_DELAY(mu) delay((mu))
+#define SCSI_LOW_SPLSCSI splbio
+#define SCSI_LOW_BZERO(pt, size) memset((pt), 0, (size))
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+#undef MSG_IDENTIFY
+#define SCSI_LOW_DEBUGGER(dev) Debugger((dev))
+#define SCSI_LOW_DELAY(mu) DELAY((mu))
+#define SCSI_LOW_SPLSCSI splcam
+#define SCSI_LOW_BZERO(pt, size) bzero((pt), (size))
+#endif /* __FreeBSD__ */
+
+/******** os depend interface structures **********/
+#ifdef __NetBSD__
+typedef struct scsipi_sense_data scsi_low_osdep_sense_data_t;
+
+struct scsi_low_osdep_interface {
+ struct device si_dev;
+
+ struct scsipi_link *si_splp;
+};
+
+struct scsi_low_osdep_targ_interface {
+};
+
+struct scsi_low_osdep_lun_interface {
+ u_int sloi_quirks;
+};
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+typedef struct scsi_sense_data scsi_low_osdep_sense_data_t;
+
+struct scsi_low_osdep_interface {
+ DEVPORT_DEVICE si_dev;
+
+ struct cam_sim *sim;
+ struct cam_path *path;
+
+ int si_poll_count;
+
+ struct callout_handle engage_ch;
+ struct callout_handle timeout_ch;
+#ifdef SCSI_LOW_POWFUNC
+ struct callout_handle recover_ch;
#endif
+};
+
+struct scsi_low_osdep_targ_interface {
+};
+
+struct scsi_low_osdep_lun_interface {
+};
+#endif /* __FreeBSD__ */
-/* user configuration flags defs */
+/******** os depend interface functions *************/
+struct slccb;
+struct scsi_low_softc;
+#define SCSI_LOW_TIMEOUT_STOP 0
+#define SCSI_LOW_TIMEOUT_START 1
+#define SCSI_LOW_TIMEOUT_CH_IO 0
+#define SCSI_LOW_TIMEOUT_CH_ENGAGE 1
+#define SCSI_LOW_TIMEOUT_CH_RECOVER 2
+
+struct scsi_low_osdep_funcs {
+ int (*scsi_low_osdep_attach) \
+ __P((struct scsi_low_softc *));
+ int (*scsi_low_osdep_world_start) \
+ __P((struct scsi_low_softc *));
+ int (*scsi_low_osdep_dettach) \
+ __P((struct scsi_low_softc *));
+ int (*scsi_low_osdep_ccb_setup) \
+ __P((struct scsi_low_softc *, struct slccb *));
+ int (*scsi_low_osdep_done) \
+ __P((struct scsi_low_softc *, struct slccb *));
+ void (*scsi_low_osdep_timeout) \
+ __P((struct scsi_low_softc *, int, int));
+};
+
+/*================================================
+ * Generic Scsi Low header file
+ * (All os depend structures should be above!)
+ ================================================*/
+/*************************************************
+ * Scsi low definitions
+ *************************************************/
#define SCSI_LOW_SYNC DVF_SCSI_SYNC
#define SCSI_LOW_DISC DVF_SCSI_DISC
#define SCSI_LOW_WAIT DVF_SCSI_WAIT
@@ -71,21 +183,22 @@
#ifndef SCSI_LOW_NTARGETS
#define SCSI_LOW_NTARGETS 8
#endif /* SCSI_LOW_NTARGETS */
-#define SCSI_LOW_NCCB 32
+#define SCSI_LOW_NCCB 128
-#define SCSI_LOW_MAX_MSGLEN 16
#define SCSI_LOW_MAX_RETRY 3
+#define SCSI_LOW_MAX_SELECTION_RETRY 10
/* timeout control macro */
-#define SCSI_LOW_MIN_TOUT 24
-#define SCSI_LOW_TIMEOUT_CHECK_INTERVAL 4
+#define SCSI_LOW_TIMEOUT_HZ 10
+#define SCSI_LOW_MIN_TOUT 12
+#define SCSI_LOW_TIMEOUT_CHECK_INTERVAL 1
#define SCSI_LOW_POWDOWN_TC 15
#define SCSI_LOW_MAX_PHCHANGES 256
+#define SCSI2_RESET_DELAY 5000000
-/* max synch period */
-#ifndef SCSI_LOW_MAX_SYNCH_SPEED
-#define SCSI_LOW_MAX_SYNCH_SPEED (100) /* 10.0M */
-#endif /* !SCSI_LOW_MAX_SYNCH_SPEED */
+/* msg */
+#define SCSI_LOW_MAX_MSGLEN 32
+#define SCSI_LOW_MSG_LOG_DATALEN 8
/*************************************************
* Scsi Data Pointer
@@ -98,31 +211,14 @@ struct sc_p {
u_int8_t *scp_cmd;
int scp_cmdlen;
- u_int scp_direction;
+ u_int8_t scp_direction;
#define SCSI_LOW_RWUNK (-1)
#define SCSI_LOW_WRITE 0
#define SCSI_LOW_READ 1
+ u_int8_t scp_status;
+ u_int8_t scp_spare[2];
};
-#define SCSI_LOW_SETUP_PHASE(ti, phase) \
-{ \
- if ((ti)->ti_phase != (phase)) \
- { \
- (ti)->ti_ophase = ti->ti_phase; \
- (ti)->ti_phase = (phase); \
- } \
-}
-
-#define SCSI_LOW_SETUP_MSGPHASE(slp, PHASE) \
-{ \
- (slp)->sl_msgphase = (PHASE); \
-}
-
-#define SCSI_LOW_TARGET_ASSERT_ATN(slp) \
-{ \
- (ti)->ti_tflags |= TARG_ASSERT_ATN; \
-}
-
/*************************************************
* Command Control Block Structure
*************************************************/
@@ -135,97 +231,163 @@ struct targ_info;
struct slccb {
TAILQ_ENTRY(slccb) ccb_chain;
-#ifdef CAM
- union ccb *ccb;
- struct buf *bp;
-#else
- struct scsipi_xfer *xs; /* scsi upper */
-#endif
+ void *osdep; /* os depend structure */
+
struct targ_info *ti; /* targ_info */
struct lun_info *li; /* lun info */
- scsi_low_tag_t ccb_tag; /* tag */
+ struct buf *bp; /* io bufs */
+
+ scsi_low_tag_t ccb_tag; /* effective qtag */
+ scsi_low_tag_t ccb_otag; /* allocated qtag */
/*****************************************
* Scsi data pointers (original and saved)
*****************************************/
struct sc_p ccb_scp; /* given */
struct sc_p ccb_sscp; /* saved scsi data pointer */
+ int ccb_datalen; /* transfered data counter */
-#ifdef SCSI_LOW_SUPPORT_USER_MSGOUT
- u_int8_t msgout[SCSI_LOW_MAX_MSGLEN]; /* scsi msgout */
- u_int msgoutlen;
-#endif /* SCSI_LOW_SUPPORT_USER_MSGOUT */
+ /*****************************************
+ * Msgout
+ *****************************************/
+ u_int ccb_msgoutflag;
+ u_int ccb_omsgoutflag;
/*****************************************
* Error or Timeout counters
*****************************************/
u_int ccb_flags;
-#define CCB_SENSE 0x01
+#define CCB_INTERNAL 0x0001
+#define CCB_SENSE 0x0002
+#define CCB_CLEARQ 0x0004
+#define CCB_DISCQ 0x0008
+#define CCB_STARTQ 0x0010
+#define CCB_POLLED 0x0100 /* polling ccb */
+#define CCB_NORETRY 0x0200 /* do NOT retry */
+#define CCB_AUTOSENSE 0x0400 /* do a sence after CA */
+#define CCB_URGENT 0x0800 /* an urgent ccb */
+#define CCB_NOSDONE 0x1000 /* do not call an os done routine */
+#define CCB_SCSIIO 0x2000 /* a normal scsi io coming from upper layer */
+#define CCB_SILENT 0x4000 /* no terminate messages */
+
u_int ccb_error;
int ccb_rcnt; /* retry counter */
+ int ccb_selrcnt; /* selection retry counter */
int ccb_tc; /* timer counter */
int ccb_tcmax; /* max timeout */
/*****************************************
* Sense data buffer
*****************************************/
-#ifdef __NetBSD__
- struct scsipi_sense ccb_sense_cmd;
- struct scsipi_sense_data ccb_sense;
-#endif
-#ifdef __FreeBSD__
- struct scsi_sense ccb_sense_cmd;
- struct scsi_sense_data ccb_sense;
-#endif
+ u_int8_t ccb_scsi_cmd[12];
+ scsi_low_osdep_sense_data_t ccb_sense;
};
-/* ccb assert */
-#ifdef __NetBSD__
-#include <dev/isa/ccbque.h>
-#endif
-#ifdef __FreeBSD__
-#include <i386/isa/ccbque.h>
-#endif
+/*************************************************
+ * Slccb functions
+ *************************************************/
GENERIC_CCB_ASSERT(scsi_low, slccb)
/*************************************************
- * Target structures
+ * Target and Lun structures
*************************************************/
struct scsi_low_softc;
+LIST_HEAD(scsi_low_softc_tab, scsi_low_softc);
TAILQ_HEAD(targ_info_tab, targ_info);
LIST_HEAD(lun_info_tab, lun_info);
struct lun_info {
+ struct scsi_low_osdep_lun_interface li_sloi;
+
int li_lun;
struct targ_info *li_ti; /* my target */
LIST_ENTRY(lun_info) lun_chain; /* targ_info link */
- int li_disc; /* num disconnects */
+ struct slccbtab li_discq; /* disconnect queue */
+
+ /*
+ * qtag control
+ */
int li_maxnexus;
+ int li_maxnqio;
+ int li_nqio;
+ int li_disc;
+
+#define SCSI_LOW_MAXNEXUS (sizeof(u_int) * NBBY)
+ u_int li_qtagbits;
+
+#ifdef SCSI_LOW_ALT_QTAG_ALLOCATE
+ u_int8_t li_qtagarray[SCSI_LOW_MAXNEXUS];
+ u_int li_qd;
+#endif /* SCSI_LOW_ALT_QTAG_ALLOCATE */
+
+#define SCSI_LOW_QFLAG_CA_QCLEAR 0x01
+ u_int li_qflags;
/*
* lun state
*/
-#define UNIT_SLEEP 0x00
-#define UNIT_START 0x01
-#define UNIT_SYNCH 0x02
-#define UNIT_WIDE 0x03
-#define UNIT_OK 0x04
-#define UNIT_NEGSTART UNIT_SYNCH
+#define SCSI_LOW_LUN_SLEEP 0x00
+#define SCSI_LOW_LUN_START 0x01
+#define SCSI_LOW_LUN_INQ 0x02
+#define SCSI_LOW_LUN_MODEQ 0x03
+#define SCSI_LOW_LUN_OK 0x04
u_int li_state; /* target lun state */
- u_int li_maxstate; /* max state */
/*
* lun control flags
*/
- u_int li_flags; /* real control flags */
- u_int li_cfgflags; /* given target cfgflags */
- u_int li_quirks; /* given target quirk */
+ u_int li_flags_valid; /* valid flags */
+#define SCSI_LOW_LUN_FLAGS_USER_VALID 0x0001
+#define SCSI_LOW_LUN_FLAGS_DISK_VALID 0x0002
+#define SCSI_LOW_LUN_FLAGS_QUIRKS_VALID 0x0004
+#define SCSI_LOW_LUN_FLAGS_ALL_VALID \
+ (SCSI_LOW_LUN_FLAGS_USER_VALID | \
+ SCSI_LOW_LUN_FLAGS_DISK_VALID | SCSI_LOW_LUN_FLAGS_QUIRKS_VALID)
+
+ u_int li_flags; /* real lun control flags */
+ u_int li_cfgflags; /* lun control flags given by user */
+ u_int li_diskflags; /* lun control flags given by hardware info */
+ u_int li_quirks; /* lun control flags given by upper layer */
+
+ /* inq buffer */
+ struct scsi_low_inq_data {
+ u_int8_t sd_type;
+ u_int8_t sd_sp1;
+ u_int8_t sd_version;
+ u_int8_t sd_resp;
+ u_int8_t sd_len;
+ u_int8_t sd_sp2[2];
+ u_int8_t sd_support;
+ } __attribute__((packed)) li_inq;
+
+ /* modeq buffer */
+ struct scsi_low_mode_sense_data {
+ u_int8_t sms_header[4];
+ struct {
+ u_int8_t cmp_page;
+ u_int8_t cmp_length;
+ u_int8_t cmp_rlec;
+ u_int8_t cmp_qc;
+ u_int8_t cmp_eca;
+ u_int8_t cmp_spare[3];
+ } __attribute__((packed)) sms_cmp;
+
+ } li_sms;
+};
+
+struct scsi_low_msg_log {
+ int slml_ptr;
+ struct {
+ u_int8_t msg[2];
+ } slml_msg[SCSI_LOW_MSG_LOG_DATALEN];
};
struct targ_info {
+ struct scsi_low_osdep_targ_interface ti_slti;
+
TAILQ_ENTRY(targ_info) ti_chain; /* targ_info link */
struct scsi_low_softc *ti_sc; /* our softc */
@@ -237,21 +399,13 @@ struct targ_info {
struct lun_info_tab ti_litab; /* lun chain */
/*
- * Nexus
+ * total disconnected nexus
*/
- struct slccb *ti_nexus; /* current nexus */
- struct lun_info *ti_li; /* current nexus lun_info */
-
- /*
- * Target status
- */
-#define TARG_ASSERT_ATN 0x01
- u_int ti_tflags; /* target state I */
+ int ti_disc;
/*
* Scsi phase control
*/
- struct slccbtab ti_discq; /* disconnect queue */
#define PH_NULL 0x00
#define PH_ARBSTART 0x01
@@ -268,23 +422,12 @@ struct targ_info {
u_int ti_ophase; /* old scsi phase */
/*
- * Status in
- */
- u_int8_t ti_status; /* status in */
-
- /*
* Msg in
*/
u_int ti_msginptr; /* msgin ptr */
u_int ti_msginlen; /* expected msg length */
+ int ti_msgin_parity_error; /* parity error detected */
u_int8_t ti_msgin[SCSI_LOW_MAX_MSGLEN]; /* msgin buffer */
- u_int ti_sphase;
-
-#ifdef SCSI_LOW_DIAGNOSTIC
-#define MSGIN_HISTORY_LEN 5
- u_int8_t ti_msgin_history[MSGIN_HISTORY_LEN];
- int ti_msgin_hist_pointer;
-#endif /* SCSI_LOW_DIAGNOSTIC */
/*
* Msg out
@@ -293,15 +436,21 @@ struct targ_info {
u_int ti_omsgflags; /* msgs asserted */
u_int ti_emsgflags; /* a msg currently asserted */
#define SCSI_LOW_MSG_RESET 0x00000001
-#define SCSI_LOW_MSG_ABORT 0x00000002
-#define SCSI_LOW_MSG_REJECT 0x00000004
-#define SCSI_LOW_MSG_PARITY 0x00000008
-#define SCSI_LOW_MSG_ERROR 0x00000010
-#define SCSI_LOW_MSG_IDENTIFY 0x00000020
-#define SCSI_LOW_MSG_SYNCH 0x00000040
-#define SCSI_LOW_MSG_WIDE 0x00000080
-#define SCSI_LOW_MSG_USER 0x00000100
-#define SCSI_LOW_MSG_NOOP 0x00000200
+#define SCSI_LOW_MSG_REJECT 0x00000002
+#define SCSI_LOW_MSG_PARITY 0x00000004
+#define SCSI_LOW_MSG_ERROR 0x00000008
+#define SCSI_LOW_MSG_IDENTIFY 0x00000010
+#define SCSI_LOW_MSG_ABORT 0x00000020
+#define SCSI_LOW_MSG_TERMIO 0x00000040
+#define SCSI_LOW_MSG_SIMPLE_QTAG 0x00000080
+#define SCSI_LOW_MSG_ORDERED_QTAG 0x00000100
+#define SCSI_LOW_MSG_HEAD_QTAG 0x00000200
+#define SCSI_LOW_MSG_ABORT_QTAG 0x00000400
+#define SCSI_LOW_MSG_CLEAR_QTAG 0x00000800
+#define SCSI_LOW_MSG_WIDE 0x00001000
+#define SCSI_LOW_MSG_SYNCH 0x00002000
+#define SCSI_LOW_MSG_NOOP 0x00004000
+#define SCSI_LOW_MSG_LAST 0x00008000
#define SCSI_LOW_MSG_ALL 0xffffffff
/* msgout buffer */
@@ -309,75 +458,108 @@ struct targ_info {
u_int ti_msgoutlen; /* msgout strlen */
/*
- * synch and wide data
+ * target initialize msgout
*/
+ u_int ti_setup_msg; /* setup msgout requests */
+ u_int ti_setup_msg_done;
+
+ /*
+ * synch and wide data info
+ */
+ u_int ti_flags_valid; /* valid flags */
+#define SCSI_LOW_TARG_FLAGS_USER_VALID 0x0001
+#define SCSI_LOW_TARG_FLAGS_DISK_VALID 0x0002
+#define SCSI_LOW_TARG_FLAGS_QUIRKS_VALID 0x0004
+#define SCSI_LOW_TARG_FLAGS_ALL_VALID \
+ (SCSI_LOW_TARG_FLAGS_USER_VALID | \
+ SCSI_LOW_TARG_FLAGS_DISK_VALID | SCSI_LOW_TARG_FLAGS_QUIRKS_VALID)
+
+ u_int ti_diskflags; /* given target disk flags */
+ u_int ti_quirks; /* given target quirk */
+
struct synch {
u_int8_t offset;
u_int8_t period;
- } ti_maxsynch; /* synch data */
+ } ti_osynch, ti_maxsynch; /* synch data */
+
+#define SCSI_LOW_BUS_WIDTH_8 0
+#define SCSI_LOW_BUS_WIDTH_16 1
+#define SCSI_LOW_BUS_WIDTH_32 2
+ u_int ti_owidth, ti_width;
- u_int ti_width;
+ /*
+ * lun info size.
+ */
+ int ti_lunsize;
+
+#ifdef SCSI_LOW_DIAGNOSTIC
+ struct scsi_low_msg_log ti_log_msgout;
+ struct scsi_low_msg_log ti_log_msgin;
+#endif /* SCSI_LOW_DIAGNOSTIC */
};
/*************************************************
* COMMON HEADER STRUCTURE
*************************************************/
struct scsi_low_softc;
+struct proc;
typedef struct scsi_low_softc *sc_low_t;
#define SCSI_LOW_START_OK 0
#define SCSI_LOW_START_FAIL 1
+#define SCSI_LOW_INFO_ALLOC 0
+#define SCSI_LOW_INFO_REVOKE 1
+#define SCSI_LOW_INFO_DEALLOC 2
+#define SCSI_LOW_POWDOWN 1
+#define SCSI_LOW_ENGAGE 2
#define SC_LOW_INIT_T (int (*) __P((sc_low_t, int)))
#define SC_LOW_BUSRST_T (void (*) __P((sc_low_t)))
-#define SC_LOW_TARG_INIT_T (int (*) __P((sc_low_t, struct targ_info *)))
+#define SC_LOW_TARG_INIT_T (int (*) __P((sc_low_t, struct targ_info *, int)))
+#define SC_LOW_LUN_INIT_T (int (*) __P((sc_low_t, struct targ_info *, struct lun_info *, int)))
#define SC_LOW_SELECT_T (int (*) __P((sc_low_t, struct slccb *)))
#define SC_LOW_ATTEN_T (void (*) __P((sc_low_t)))
-#define SC_LOW_NEXUS_T (int (*) __P((sc_low_t, struct targ_info *)))
+#define SC_LOW_NEXUS_T (int (*) __P((sc_low_t)))
#define SC_LOW_MSG_T (int (*) __P((sc_low_t, struct targ_info *, u_int)))
#define SC_LOW_POLL_T (int (*) __P((void *)))
#define SC_LOW_POWER_T (int (*) __P((sc_low_t, u_int)))
+#define SC_LOW_TIMEOUT_T (int (*) __P((sc_low_t)))
struct scsi_low_funcs {
int (*scsi_low_init) __P((sc_low_t, int));
void (*scsi_low_bus_reset) __P((sc_low_t));
- int (*scsi_low_targ_init) __P((sc_low_t, struct targ_info *));
-
+ int (*scsi_low_targ_init) __P((sc_low_t, struct targ_info *, int));
+ int (*scsi_low_lun_init) __P((sc_low_t, struct targ_info *, struct lun_info *, int));
int (*scsi_low_start_bus) __P((sc_low_t, struct slccb *));
- int (*scsi_low_establish_nexus) __P((sc_low_t, struct targ_info *));
-
+ int (*scsi_low_establish_lun_nexus) __P((sc_low_t));
+ int (*scsi_low_establish_ccb_nexus) __P((sc_low_t));
void (*scsi_low_attention) __P((sc_low_t));
int (*scsi_low_msg) __P((sc_low_t, struct targ_info *, u_int));
-
+ int (*scsi_low_timeout) __P((sc_low_t));
int (*scsi_low_poll) __P((void *));
-
-#define SCSI_LOW_POWDOWN 1
-#define SCSI_LOW_ENGAGE 2
int (*scsi_low_power) __P((sc_low_t, u_int));
+ int (*scsi_low_ioctl) __P((sc_low_t, u_long, caddr_t, int, struct proc *));
};
-/*************************************************
- * SCSI LOW SOFTC
- *************************************************/
struct scsi_low_softc {
- DEVPORT_DEVICE sl_dev;
+ /* os depend structure */
+ struct scsi_low_osdep_interface sl_si;
+#define sl_dev sl_si.si_dev
+ struct scsi_low_osdep_funcs *sl_osdep_fp;
u_char sl_xname[16];
- /* upper interface */
-#ifdef CAM
- struct cam_sim *sim;
- struct cam_path *path;
-#else
- struct scsipi_link sl_link;
-#endif
+ /* our chain */
+ LIST_ENTRY(scsi_low_softc) sl_chain;
/* my targets */
struct targ_info *sl_ti[SCSI_LOW_NTARGETS];
struct targ_info_tab sl_titab;
- /* current active nexus */
+ /* current active T_L_Q nexus */
+ struct targ_info *sl_Tnexus; /* Target nexus */
+ struct lun_info *sl_Lnexus; /* Lun nexus */
+ struct slccb *sl_Qnexus; /* Qtag nexus */
int sl_nexus_call;
- struct targ_info *sl_nexus;
/* ccb start queue */
struct slccbtab sl_start;
@@ -385,29 +567,45 @@ struct scsi_low_softc {
/* retry limit and phase change counter */
int sl_max_retry;
int sl_ph_count;
+ int sl_timeout_count;
/* selection & total num disconnect targets */
+ int sl_nio;
int sl_disc;
- struct targ_info *sl_selid;
+ int sl_retry_sel;
+ struct slccb *sl_selid;
- /* scsi phased suggested by scsi msg */
+ /* attention */
+ int sl_atten; /* ATN asserted */
+ int sl_clear_atten; /* negate ATN required */
+
+ /* scsi phase suggested by scsi msg */
u_int sl_msgphase;
#define MSGPH_NULL 0x00 /* no msg */
#define MSGPH_DISC 0x01 /* disconnect msg */
#define MSGPH_CMDC 0x02 /* cmd complete msg */
+#define MSGPH_ABORT 0x03 /* abort seq */
+#define MSGPH_TERM 0x04 /* current io terminate */
+#define MSGPH_LCTERM 0x05 /* cmd link terminated */
+#define MSGPH_RESET 0x06 /* reset target */
/* error */
-#define FATALIO 0x01 /* generic io error & retry io */
-#define ABORTIO 0x02 /* generic io error & terminate io */
-#define TIMEOUTIO 0x04 /* watch dog timeout */
-#define SELTIMEOUTIO 0x08 /* selection timeout */
-#define PDMAERR 0x10 /* dma xfer error */
-#define MSGERR 0x20 /* msgsys error */
-#define PARITYERR 0x40 /* parity error */
-#define BUSYERR 0x80 /* target busy error */
-#define CMDREJECT 0x100 /* cmd reject error */
-#define SCSI_LOW_ERRORBITS "\020\009cmdrej\008busy\007parity\006msgerr\005pdmaerr\004seltimeout\003timeout\002abort\001fatal"
- u_int sl_error; /* error flags */
+ u_int sl_error; /* error flags */
+#define FATALIO 0x0001 /* generic io error & retry io */
+#define ABORTIO 0x0002 /* generic io error & terminate io */
+#define TIMEOUTIO 0x0004 /* watch dog timeout */
+#define SELTIMEOUTIO 0x0008 /* selection timeout */
+#define PDMAERR 0x0010 /* dma xfer error */
+#define MSGERR 0x0020 /* msgsys error */
+#define PARITYERR 0x0040 /* parity error */
+#define BUSYERR 0x0080 /* target busy error */
+#define STATERR 0x0100 /* status error */
+#define UACAERR 0x0200 /* target CA state, no sense check */
+#define SENSEIO 0x1000 /* cmd not excuted but sense data ok */
+#define SENSEERR 0x2000 /* cmd not excuted and sense data bad */
+#define UBFERR 0x4000 /* unexpected bus free */
+#define PENDINGIO 0x8000 /* ccb start not yet */
+#define SCSI_LOW_ERRORBITS "\020\017ubferr\016senseerr\015senseio\012uacaerr\011staterr\010busy\007parity\006msgerr\005pdmaerr\004seltimeout\003timeout\002abort\001fatal"
/* current scsi data pointer */
struct sc_p sl_scp;
@@ -419,18 +617,28 @@ struct scsi_low_softc {
/* configuration flags */
u_int sl_flags;
-#define HW_POWDOWN 0x01
-#define HW_RESUME 0x02
-#define HW_PDMASTART 0x04
-#define HW_INACTIVE 0x08
-#define HW_POWERCTRL 0x10
+#define HW_POWDOWN 0x0001
+#define HW_RESUME 0x0002
+#define HW_PDMASTART 0x0004
+#define HW_INACTIVE 0x0008
+#define HW_POWERCTRL 0x0010
+#define HW_INITIALIZING 0x0020
+#define HW_READ_PADDING 0x1000
+#define HW_WRITE_PADDING 0x2000
u_int sl_cfgflags;
-#define CFG_NODISC 0x01
-#define CFG_NOPARITY 0x02
-#define CFG_NOATTEN 0x04
-#define CFG_ASYNC 0x08
-#define CFG_MSGUNIFY 0x10
+#define CFG_NODISC 0x0001
+#define CFG_NOPARITY 0x0002
+#define CFG_NOATTEN 0x0004
+#define CFG_ASYNC 0x0008
+#define CFG_NOQTAG 0x0010
+
+ int sl_show_result;
+#define SHOW_SYNCH_NEG 0x0001
+#define SHOW_WIDE_NEG 0x0002
+#define SHOW_CALCF_RES 0x0010
+#define SHOW_PROBE_RES 0x0020
+#define SHOW_ALL_NEG -1
/* host informations */
u_int sl_hostid;
@@ -441,16 +649,12 @@ struct scsi_low_softc {
/* interface functions */
struct scsi_low_funcs *sl_funcs;
-#if defined(__i386__)
+ /* targinfo size */
+ int sl_targsize;
+
+#if defined(i386) || defined(__i386__)
u_int sl_irq; /* XXX */
#endif /* i386 */
-#ifdef __FreeBSD__
- struct callout_handle engage_ch;
- struct callout_handle timeout_ch;
-#ifdef SCSI_LOW_POWFUNC
- struct callout_handle recover_ch;
-#endif
-#endif /* __FreeBSD__ */
};
/*************************************************
@@ -459,26 +663,49 @@ struct scsi_low_softc {
/*
* Scsi low attachment function.
*/
-int scsi_low_attach __P((struct scsi_low_softc *, int, int, int, int));
+int scsi_low_attach __P((struct scsi_low_softc *, int, int, int, int, int));
int scsi_low_dettach __P((struct scsi_low_softc *));
/*
+ * Scsi low interface activate or deactivate functions
+ */
+int scsi_low_is_busy __P((struct scsi_low_softc *));
+int scsi_low_activate __P((struct scsi_low_softc *));
+int scsi_low_deactivate __P((struct scsi_low_softc *));
+
+/*
* Scsi phase "bus service" functions.
* These functions are corresponding to each scsi bus phaeses.
*/
-/* nexus abort (selection failed) */
-void scsi_low_clear_nexus __P((struct scsi_low_softc *, struct targ_info *));
+/* bus idle phase (other initiators or targets release bus) */
+void scsi_low_bus_idle __P((struct scsi_low_softc *));
+
+/* arbitration and selection phase */
+void scsi_low_arbit_fail __P((struct scsi_low_softc *, struct slccb *));
+static __inline void scsi_low_arbit_win __P((struct scsi_low_softc *));
+
/* msgout phase */
-int scsi_low_msgout __P((struct scsi_low_softc *, struct targ_info *));
+#define SCSI_LOW_MSGOUT_INIT 0x00000001
+#define SCSI_LOW_MSGOUT_UNIFY 0x00000002
+int scsi_low_msgout __P((struct scsi_low_softc *, struct targ_info *, u_int));
+
/* msgin phase */
-void scsi_low_msgin __P((struct scsi_low_softc *, struct targ_info *, u_int8_t));
+#define SCSI_LOW_DATA_PE 0x80000000
+int scsi_low_msgin __P((struct scsi_low_softc *, struct targ_info *, u_int));
+
+/* statusin phase */
+static __inline int scsi_low_statusin __P((struct scsi_low_softc *, struct targ_info *, u_int));
+
/* data phase */
int scsi_low_data __P((struct scsi_low_softc *, struct targ_info *, struct buf **, int));
+static __inline void scsi_low_data_finish __P((struct scsi_low_softc *));
+
/* cmd phase */
int scsi_low_cmd __P((struct scsi_low_softc *, struct targ_info *));
/* reselection phase */
struct targ_info *scsi_low_reselected __P((struct scsi_low_softc *, u_int));
+
/* disconnection phase */
int scsi_low_disconnected __P((struct scsi_low_softc *, struct targ_info *));
@@ -495,52 +722,70 @@ int scsi_low_restart __P((struct scsi_low_softc *, int, u_char *));
*/
/* print current status */
void scsi_low_print __P((struct scsi_low_softc *, struct targ_info *));
-/* timeout utility (only in used scsi_low_pisa) */
-void scsi_low_timeout __P((void *));
-#define SCSI2_RESET_DELAY 5000000
-#define TWIDDLEWAIT 10000
+
/* bus reset utility */
void scsi_low_bus_reset __P((struct scsi_low_softc *));
/*************************************************
- * Inline utility
+ * Message macro defs
*************************************************/
-static __inline u_int8_t scsi_low_identify __P((struct targ_info *ti));
-static __inline void scsi_low_attention __P((struct scsi_low_softc *, struct targ_info *));
-static __inline int scsi_low_is_msgout_continue __P((struct targ_info *));
+#define SCSI_LOW_SETUP_PHASE(ti, phase) \
+{ \
+ (ti)->ti_ophase = ti->ti_phase; \
+ (ti)->ti_phase = (phase); \
+}
+
+#define SCSI_LOW_SETUP_MSGPHASE(slp, PHASE) \
+{ \
+ (slp)->sl_msgphase = (PHASE); \
+}
+
+#define SCSI_LOW_ASSERT_ATN(slp) \
+{ \
+ (slp)->sl_atten = 1; \
+}
+
+#define SCSI_LOW_DEASSERT_ATN(slp) \
+{ \
+ (slp)->sl_atten = 0; \
+}
+
+/*************************************************
+ * Inline functions
+ *************************************************/
+static __inline void scsi_low_attention __P((struct scsi_low_softc *));
+static __inline int scsi_low_is_msgout_continue __P((struct targ_info *, u_int));
static __inline int scsi_low_assert_msg __P((struct scsi_low_softc *, struct targ_info *, u_int, int));
-static __inline void scsi_low_arbit_win __P((struct scsi_low_softc *, struct targ_info *));
+static __inline int scsi_low_is_disconnect_ok __P((struct slccb *));
static __inline int
-scsi_low_is_msgout_continue(ti)
+scsi_low_is_msgout_continue(ti, mask)
struct targ_info *ti;
+ u_int mask;
{
- return (ti->ti_msgflags != 0);
+ return ((ti->ti_msgflags & (~mask)) != 0);
}
-static __inline u_int8_t
-scsi_low_identify(ti)
- struct targ_info *ti;
+static __inline int
+scsi_low_is_disconnect_ok(cb)
+ struct slccb *cb;
{
- u_int8_t msg;
- struct lun_info *li = ti->ti_li;
- msg = (li->li_flags & SCSI_LOW_DISC) ? 0xc0 : 0x80;
- msg |= li->li_lun;
- return msg;
+ return ((cb->li->li_flags & SCSI_LOW_DISC) != 0 &&
+ (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) == 0);
}
-#define ID_MSG_SETUP(ti) (scsi_low_identify(ti))
-
static __inline void
-scsi_low_attention(slp, ti)
+scsi_low_attention(slp)
struct scsi_low_softc *slp;
- struct targ_info *ti;
{
+ if (slp->sl_atten != 0)
+ return;
+
(*slp->sl_funcs->scsi_low_attention) (slp);
- SCSI_LOW_TARGET_ASSERT_ATN(slp);
+ SCSI_LOW_ASSERT_ATN(slp);
}
static __inline int
@@ -553,19 +798,46 @@ scsi_low_assert_msg(slp, ti, msg, now)
ti->ti_msgflags |= msg;
if (now != 0)
- scsi_low_attention(slp, ti);
+ scsi_low_attention(slp);
return 0;
}
static __inline void
-scsi_low_arbit_win(slp, ti)
+scsi_low_arbit_win(slp)
struct scsi_low_softc *slp;
- struct targ_info *ti;
{
slp->sl_selid = NULL;
}
+static __inline void
+scsi_low_data_finish(slp)
+ struct scsi_low_softc *slp;
+{
+
+ if (slp->sl_Qnexus != NULL)
+ {
+ slp->sl_Qnexus->ccb_datalen = slp->sl_scp.scp_datalen;
+ }
+}
+
+static __inline int
+scsi_low_statusin(slp, ti, c)
+ struct scsi_low_softc *slp;
+ struct targ_info *ti;
+ u_int c;
+{
+
+ slp->sl_ph_count ++;
+ if ((c & SCSI_LOW_DATA_PE) != 0)
+ {
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 0);
+ return EIO;
+ }
+ slp->sl_scp.scp_status = (u_int8_t) c;
+ return 0;
+}
+
/*************************************************
* Message out defs
*************************************************/
@@ -577,7 +849,9 @@ scsi_low_arbit_win(slp, ti)
#define ST_INTERGOOD 0x10
#define ST_INTERMET 0x14
#define ST_CONFLICT 0x18
+#define ST_CMDTERM 0x22
#define ST_QUEFULL 0x28
+#define ST_UNKNOWN 0xff
#define MSG_COMP 0x00
#define MSG_EXTEND 0x01
@@ -601,10 +875,12 @@ scsi_low_arbit_win(slp, ti)
#define MSG_LCOMP 0x0a
#define MSG_LCOMP_F 0x0b
#define MSG_RESET 0x0c
-#ifdef __FreeBSD__
-#undef MSG_IDENTIFY
-#endif
-#define MSG_IDENTIFY 0x80
-
-#define OS_DEPEND(s) (s)
+#define MSG_ABORT_QTAG 0x0d
+#define MSG_CLEAR_QTAG 0x0e
+#define MSG_TERM_IO 0x11
+#define MSG_SIMPLE_QTAG 0x20
+#define MSG_HEAD_QTAG 0x21
+#define MSG_ORDERED_QTAG 0x22
+#define MSG_IDENTIFY 0x80
+#define MSG_IDENTIFY_DISCPRIV 0x40
#endif /* !_SCSI_LOW_H_ */
diff --git a/sys/cam/scsi/scsi_low_pisa.c b/sys/cam/scsi/scsi_low_pisa.c
index c9510bd..d15367b 100644
--- a/sys/cam/scsi/scsi_low_pisa.c
+++ b/sys/cam/scsi/scsi_low_pisa.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $NecBSD: scsi_low_pisa.c,v 1.13 1998/11/26 14:26:11 honda Exp $ */
+/* $NecBSD: scsi_low_pisa.c,v 1.13.18.1 2001/06/08 06:27:48 honda Exp $ */
/* $NetBSD$ */
/*
@@ -33,25 +33,16 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#ifdef __NetBSD__
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#ifdef __NetBSD__
-#include <sys/disklabel.h>
-#endif
-#if defined(__FreeBSD__) && __FreeBSD_version >= 500001
-#include <sys/bio.h>
-#endif
-#include <sys/buf.h>
-#include <sys/queue.h>
-#include <sys/device_port.h>
+#include <sys/device.h>
+#include <sys/errno.h>
-#ifdef __NetBSD__
#include <machine/bus.h>
#include <machine/intr.h>
-#endif
-#ifdef __NetBSD__
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
@@ -68,93 +59,44 @@
#include <i386/Cbus/dev/scsi_low_pisa.h>
#define SCSIBUS_RESCAN
-#else
-#ifdef __FreeBSD__
-#include <cam/scsi/scsi_low.h>
-#include <cam/scsi/scsi_low_pisa.h>
-#endif
-#endif
-#ifdef __FreeBSD__
int
-scsi_low_deactivate(struct scsi_low_softc *sc)
-{
-#else
-#ifdef __NetBSD__
-int
-scsi_low_deactivate(dh)
+scsi_low_deactivate_pisa(dh)
pisa_device_handle_t dh;
{
struct scsi_low_softc *sc = PISA_DEV_SOFTC(dh);
-#endif
-#endif
- sc->sl_flags |= HW_INACTIVE;
-
-#ifdef __NetBSD__
-#ifdef SCSI_LOW_POWFUNC
- untimeout(scsi_low_recover, sc);
-#endif /* SCSI_LOW_POWFUNC */
- untimeout(scsi_low_timeout, sc);
-#else
-#ifdef __FreeBSD__
-#ifdef SCSI_LOW_POWFUNC
- untimeout(scsi_low_recover, sc, sc->recover_ch);
-#endif /* SCSI_LOW_POWFUNC */
- untimeout(scsi_low_timeout, sc, sc->timeout_ch);
-#endif
-#endif
+ if (scsi_low_deactivate(sc) != 0)
+ return EBUSY;
return 0;
}
-#ifdef __FreeBSD__
int
-scsi_low_activate(struct scsi_low_softc *sc, int flags)
-{
-#else
-#ifdef __NetBSD__
-int
-scsi_low_activate(dh)
+scsi_low_activate_pisa(dh)
pisa_device_handle_t dh;
{
struct scsi_low_softc *sc = PISA_DEV_SOFTC(dh);
slot_device_res_t dr = PISA_RES_DR(dh);
-#endif
-#endif
- int error;
- sc->sl_flags &= ~HW_INACTIVE;
-#ifdef __FreeBSD__
- sc->sl_cfgflags = ((sc->sl_cfgflags & 0xffff0000) |
- (flags & 0x00ff));
-#else /* __NetBSD__ */
sc->sl_cfgflags = DVCFG_MKCFG(DVCFG_MAJOR(sc->sl_cfgflags), \
DVCFG_MINOR(PISA_DR_DVCFG(dr)));
sc->sl_irq = PISA_DR_IRQ(dr);
-#endif
- if ((error = scsi_low_restart(sc, SCSI_LOW_RESTART_HARD, NULL)) != 0)
- {
- sc->sl_flags |= HW_INACTIVE;
- return error;
- }
+ if (scsi_low_activate(sc) != 0)
+ return EBUSY;
-#ifdef __FreeBSD__
- sc->timeout_ch =
-#endif
- timeout(scsi_low_timeout, sc, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz);
/* rescan the scsi bus */
#ifdef SCSIBUS_RESCAN
- if (PISA_RES_EVENT(dh) == PISA_EVENT_INSERT &&
- TAILQ_FIRST(&sc->sl_start) == NULL)
- scsi_probe_busses((int) sc->sl_link.scsipi_scsi.scsibus, -1, -1);
+ if (scsi_low_is_busy(sc) == 0 &&
+ PISA_RES_EVENT(dh) == PISA_EVENT_INSERT)
+ scsi_probe_busses((int) sc->sl_si.si_splp->scsipi_scsi.scsibus,
+ -1, -1);
#endif
return 0;
}
-#ifdef __NetBSD__
int
-scsi_low_notify(dh, ev)
+scsi_low_notify_pisa(dh, ev)
pisa_device_handle_t dh;
pisa_event_t ev;
{
@@ -163,7 +105,7 @@ scsi_low_notify(dh, ev)
switch(ev)
{
case PISA_EVENT_QUERY_SUSPEND:
- if (TAILQ_FIRST(&sc->sl_start) != NULL)
+ if (scsi_low_is_busy(sc) != 0)
return SD_EVENT_STATUS_BUSY;
break;
@@ -172,4 +114,43 @@ scsi_low_notify(dh, ev)
}
return 0;
}
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#if __FreeBSD_version >= 500001
+#include <sys/bio.h>
#endif
+#include <sys/buf.h>
+#include <sys/queue.h>
+#include <sys/device_port.h>
+
+#include <cam/scsi/scsi_low.h>
+#include <cam/scsi/scsi_low_pisa.h>
+
+int
+scsi_low_deactivate_pisa(sc)
+ struct scsi_low_softc *sc;
+{
+
+ if (scsi_low_deactivate(sc) != 0)
+ return EBUSY;
+ return 0;
+}
+
+int
+scsi_low_activate_pisa(sc, flags)
+ struct scsi_low_softc *sc;
+ int flags;
+{
+
+ sc->sl_cfgflags = ((sc->sl_cfgflags & 0xffff0000) |
+ (flags & 0x00ff));
+
+ if (scsi_low_activate(sc) != 0)
+ return EBUSY;
+ return 0;
+}
+#endif /* __FreeBSD__ */
diff --git a/sys/cam/scsi/scsi_low_pisa.h b/sys/cam/scsi/scsi_low_pisa.h
index 8a8a542..f890a06 100644
--- a/sys/cam/scsi/scsi_low_pisa.h
+++ b/sys/cam/scsi/scsi_low_pisa.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $NecBSD: scsi_low_pisa.h,v 1.3 1999/04/15 01:35:57 kmatsuda Exp $ */
+/* $NecBSD: scsi_low_pisa.h,v 1.3.14.1 2001/06/08 06:27:49 honda Exp $ */
/* $NetBSD$ */
/*
@@ -34,13 +34,14 @@
#ifndef _SCSI_LOW_PISA_H_
#define _SCSI_LOW_PISA_H_
-#ifdef __NetBSD__
-int scsi_low_activate __P((pisa_device_handle_t));
-int scsi_low_deactivate __P((pisa_device_handle_t));
-int scsi_low_notify __P((pisa_device_handle_t, pisa_event_t));
-#endif
-#ifdef __FreeBSD__
-int scsi_low_activate __P((struct scsi_low_softc *, int));
-int scsi_low_deactivate __P((struct scsi_low_softc *));
-#endif
+#ifdef __NetBSD__
+int scsi_low_activate_pisa __P((pisa_device_handle_t));
+int scsi_low_deactivate_pisa __P((pisa_device_handle_t));
+int scsi_low_notify_pisa __P((pisa_device_handle_t, pisa_event_t));
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+int scsi_low_activate_pisa __P((struct scsi_low_softc *, int));
+int scsi_low_deactivate_pisa __P((struct scsi_low_softc *));
+#endif /* __FreeBSD__ */
#endif /* !_SCSI_LOW_PISA_H_ */
diff --git a/sys/conf/options.pc98 b/sys/conf/options.pc98
index 54695aa..1de95c4 100644
--- a/sys/conf/options.pc98
+++ b/sys/conf/options.pc98
@@ -188,6 +188,10 @@ NDGBPORTS opt_dgb.h
SCSI_BOUNCE_SIZE opt_bs.h
BS_TARG_SAFEMODE opt_bs.h
+# ct driver options
+CT_USE_RELOCATE_OFFSET opt_ct.h
+CT_BUS_WEIGHT opt_ct.h
+
# npx options
FPU_ERROR_BROKEN opt_npx.h
diff --git a/sys/dev/ct/bshw_machdep.c b/sys/dev/ct/bshw_machdep.c
index 6b375ab..c7995ce 100644
--- a/sys/dev/ct/bshw_machdep.c
+++ b/sys/dev/ct/bshw_machdep.c
@@ -1,13 +1,13 @@
/* $FreeBSD$ */
-/* $NecBSD: bshw_machdep.c,v 1.8 1999/07/23 20:54:00 honda Exp $ */
+/* $NecBSD: bshw_machdep.c,v 1.8.12.6 2001/06/29 06:28:05 honda Exp $ */
/* $NetBSD$ */
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999
+ * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
*
- * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999
+ * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
* Naofumi HONDA. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,18 +39,19 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/disklabel.h>
+#if defined(__FreeBSD__) && __FreeBSD_version > 500001
#include <sys/bio.h>
+#endif /* __ FreeBSD__ */
#include <sys/buf.h>
#include <sys/queue.h>
#include <sys/malloc.h>
-#include <sys/device_port.h>
#include <sys/errno.h>
#include <vm/vm.h>
-#include <vm/pmap.h>
#ifdef __NetBSD__
+#include <sys/device.h>
+
#include <machine/bus.h>
#include <machine/intr.h>
@@ -66,6 +67,7 @@
#include <dev/ic/wd33c93reg.h>
#include <i386/Cbus/dev/ct/ctvar.h>
+#include <i386/Cbus/dev/ct/ct_machdep.h>
#include <i386/Cbus/dev/ct/bshwvar.h>
#endif /* __NetBSD__ */
@@ -73,7 +75,6 @@
#include <machine/bus.h>
#include <machine/clock.h>
#include <machine/md_var.h>
-#include <machine/pmap.h>
#include <machine/dvcfg.h>
#include <machine/physio_proc.h>
@@ -82,32 +83,50 @@
#include <dev/ic/wd33c93reg.h>
#include <dev/ct/ctvar.h>
+#include <dev/ct/ct_machdep.h>
#include <dev/ct/bshwvar.h>
+
+#include <vm/pmap.h>
+#endif /* __FreeBSD__ */
+
+#define BSHW_IO_CONTROL_FLAGS 0
+
+u_int bshw_io_control = BSHW_IO_CONTROL_FLAGS;
+int bshw_data_read_bytes = 4096;
+int bshw_data_write_bytes = 4096;
+
+/*********************************************************
+ * OS dep part
+ *********************************************************/
+#ifdef __NetBSD__
+#define BSHW_PAGE_SIZE NBPG
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+#define BSHW_PAGE_SIZE PAGE_SIZE
+typedef unsigned long vaddr_t;
#endif /* __FreeBSD__ */
/*********************************************************
* GENERIC MACHDEP FUNCTIONS
*********************************************************/
void
-bshw_synch_setup(ct, li)
+bshw_synch_setup(ct, ti)
struct ct_softc *ct;
- struct lun_info *li;
+ struct targ_info *ti;
{
- struct scsi_low_softc *slp = &ct->sc_sclow;
- struct targ_info *ti = slp->sl_nexus;
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
struct ct_targ_info *cti = (void *) ti;
struct bshw_softc *bs = ct->ct_hw;
struct bshw *hw = bs->sc_hw;
- if (hw->sregaddr == 0)
+ if (hw->hw_sregaddr == 0)
return;
- ct_cr_write_1(bst, bsh, hw->sregaddr + ti->ti_id, cti->cti_syncreg);
+ ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id, cti->cti_syncreg);
if (hw->hw_flags & BSHW_DOUBLE_DMACHAN)
{
- ct_cr_write_1(bst, bsh, hw->sregaddr + ti->ti_id + 8,
+ ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id + 8,
cti->cti_syncreg);
}
}
@@ -117,8 +136,7 @@ bshw_bus_reset(ct)
struct ct_softc *ct;
{
struct scsi_low_softc *slp = &ct->sc_sclow;
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
struct bshw_softc *bs = ct->ct_hw;
struct bshw *hw = bs->sc_hw;
bus_addr_t offs;
@@ -126,53 +144,52 @@ bshw_bus_reset(ct)
int i;
/* open hardware busmaster mode */
- if (hw->dma_init != NULL && ((*hw->dma_init)(ct)) != 0)
+ if (hw->hw_dma_init != NULL && ((*hw->hw_dma_init)(ct)) != 0)
{
- printf("%s change mode using external DMA (%x)\n",
- slp->sl_xname, (u_int)ct_cr_read_1(bst, bsh, 0x37));
+ printf("%s: change mode using external DMA (%x)\n",
+ slp->sl_xname, (u_int)ct_cr_read_1(chp, 0x37));
}
/* clear hardware synch registers */
- offs = hw->sregaddr;
+ offs = hw->hw_sregaddr;
if (offs != 0)
{
for (i = 0; i < 8; i ++, offs ++)
{
- ct_cr_write_1(bst, bsh, offs, 0);
+ ct_cr_write_1(chp, offs, 0);
if ((hw->hw_flags & BSHW_DOUBLE_DMACHAN) != 0)
- ct_cr_write_1(bst, bsh, offs + 8, 0);
+ ct_cr_write_1(chp, offs + 8, 0);
}
}
/* disable interrupt & assert reset */
- regv = ct_cr_read_1(bst, bsh, wd3s_mbank);
+ regv = ct_cr_read_1(chp, wd3s_mbank);
regv |= MBR_RST;
regv &= ~MBR_IEN;
- ct_cr_write_1(bst, bsh, wd3s_mbank, regv);
+ ct_cr_write_1(chp, wd3s_mbank, regv);
- delay(500000);
+ SCSI_LOW_DELAY(500000);
/* reset signal off */
regv &= ~MBR_RST;
- ct_cr_write_1(bst, bsh, wd3s_mbank, regv);
+ ct_cr_write_1(chp, wd3s_mbank, regv);
/* interrupt enable */
regv |= MBR_IEN;
- ct_cr_write_1(bst, bsh, wd3s_mbank, regv);
+ ct_cr_write_1(chp, wd3s_mbank, regv);
}
/* probe */
int
-bshw_read_settings(bst, bsh, bs)
- bus_space_tag_t bst;
- bus_space_handle_t bsh;
+bshw_read_settings(chp, bs)
+ struct ct_bus_access_handle *chp;
struct bshw_softc *bs;
{
static int irq_tbl[] = { 3, 5, 6, 9, 12, 13 };
- bs->sc_hostid = (ct_cr_read_1(bst, bsh, wd3s_auxc) & AUXCR_HIDM);
- bs->sc_irq = irq_tbl[(ct_cr_read_1(bst, bsh, wd3s_auxc) >> 3) & 7];
- bs->sc_drq = bus_space_read_1(bst, bsh, cmd_port) & 3;
+ bs->sc_hostid = (ct_cr_read_1(chp, wd3s_auxc) & AUXCR_HIDM);
+ bs->sc_irq = irq_tbl[(ct_cr_read_1(chp, wd3s_auxc) >> 3) & 7];
+ bs->sc_drq = ct_cmdp_read_1(chp) & 3;
return 0;
}
@@ -194,18 +211,17 @@ bshw_read_settings(bst, bsh, bs)
#define SF_RDY 0x10
static __inline void bshw_lc_smit_start __P((struct ct_softc *, int, u_int));
-static int bshw_lc_smit_fstat __P((struct ct_softc *, int, int));
static __inline void bshw_lc_smit_stop __P((struct ct_softc *));
+static int bshw_lc_smit_fstat __P((struct ct_softc *, int, int));
static __inline void
bshw_lc_smit_stop(ct)
struct ct_softc *ct;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
- ct_cr_write_1(bst, bsh, BSHW_LC_FCTRL, 0);
- bus_space_write_1(ct->sc_iot, ct->sc_ioh, cmd_port, CMDP_DMER);
+ ct_cr_write_1(chp, BSHW_LC_FCTRL, 0);
+ ct_cmdp_write_1(chp, CMDP_DMER);
}
static __inline void
@@ -214,18 +230,17 @@ bshw_lc_smit_start(ct, count, direction)
int count;
u_int direction;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
u_int8_t pval, val;
- val = ct_cr_read_1(bst, bsh, BSHW_LC_FSET);
- cthw_set_count(bst, bsh, count);
+ val = ct_cr_read_1(chp, BSHW_LC_FSET);
+ cthw_set_count(chp, count);
pval = FCTRL_EN;
if (direction == SCSI_LOW_WRITE)
pval |= (val & 0xe0) | FCTRL_WRITE;
- ct_cr_write_1(bst, bsh, BSHW_LC_FCTRL, pval);
- ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_TFR_INFO);
+ ct_cr_write_1(chp, BSHW_LC_FCTRL, pval);
+ ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO);
}
static int
@@ -233,12 +248,13 @@ bshw_lc_smit_fstat(ct, wc, read)
struct ct_softc *ct;
int wc, read;
{
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
u_int8_t stat;
while (wc -- > 0)
{
- outb(0x5f, 0);
- stat = bus_space_read_1(ct->sc_iot, ct->sc_ioh, cmd_port);
+ chp->ch_bus_weight(chp);
+ stat = ct_cmdp_read_1(chp);
if (read == SCSI_LOW_READ)
{
if ((stat & SF_RDY) != 0)
@@ -268,68 +284,85 @@ bshw_smit_xfer_stop(ct)
struct targ_info *ti;
struct sc_p *sp = &slp->sl_scp;
u_int count;
- u_char *s;
bshw_lc_smit_stop(ct);
- ti = slp->sl_nexus;
+ ti = slp->sl_Tnexus;
if (ti == NULL)
return;
if (ti->ti_phase == PH_DATA)
{
- count = cthw_get_count(ct->sc_iot, ct->sc_ioh);
- if (count < (u_int) sp->scp_datalen)
+ count = cthw_get_count(&ct->sc_ch);
+ if (count < bs->sc_sdatalen)
{
- sp->scp_data += (sp->scp_datalen - count);
- sp->scp_datalen = count;
- /* XXX:
- * strict double checks!
- * target => wd33c93c transfer counts
- * wd33c93c => memory transfer counts
- */
if (sp->scp_direction == SCSI_LOW_READ &&
- count != bs->sc_tdatalen)
- {
- s = "read count miss";
+ count != bs->sc_edatalen)
goto bad;
- }
- return;
+
+ count = bs->sc_sdatalen - count;
+ if (count > (u_int) sp->scp_datalen)
+ goto bad;
+
+ sp->scp_data += count;
+ sp->scp_datalen -= count;
}
- else if (count == (u_int) sp->scp_datalen)
+ else if (count > bs->sc_sdatalen)
{
- return;
+bad:
+ printf("%s: smit_xfer_end: cnt error\n", slp->sl_xname);
+ slp->sl_error |= PDMAERR;
}
-
- s = "strange count";
+ scsi_low_data_finish(slp);
}
else
- s = "extra smit interrupt";
-
-bad:
- printf("%s: smit_xfer_end: %s", slp->sl_xname, s);
- slp->sl_error |= PDMAERR;
+ {
+ printf("%s: smit_xfer_end: phase miss\n", slp->sl_xname);
+ slp->sl_error |= PDMAERR;
+ }
}
-void
+int
bshw_smit_xfer_start(ct)
struct ct_softc *ct;
{
struct scsi_low_softc *slp = &ct->sc_sclow;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
struct bshw_softc *bs = ct->ct_hw;
struct sc_p *sp = &slp->sl_scp;
- struct targ_info *ti = slp->sl_nexus;
+ struct targ_info *ti = slp->sl_Tnexus;
struct ct_targ_info *cti = (void *) ti;
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
- int datalen, count, wc = LC_SMIT_TIMEOUT * 1024 * 1024;
+ u_int datalen, count, io_control;
+ int wc;
u_int8_t *data;
- data = sp->scp_data;
+ io_control = bs->sc_io_control | bshw_io_control;
+ if ((io_control & BSHW_SMIT_BLOCK) != 0)
+ return EINVAL;
+
+ if ((slp->sl_scp.scp_datalen % DEV_BSIZE) != 0)
+ return EINVAL;
+
datalen = sp->scp_datalen;
+ if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
+ {
+ if ((io_control & BSHW_READ_INTERRUPT_DRIVEN) != 0 &&
+ datalen > bshw_data_read_bytes)
+ datalen = bshw_data_read_bytes;
+ }
+ else
+ {
+ if ((io_control & BSHW_WRITE_INTERRUPT_DRIVEN) != 0 &&
+ datalen > bshw_data_write_bytes)
+ datalen = bshw_data_write_bytes;
+ }
+
+ bs->sc_sdatalen = datalen;
+ data = sp->scp_data;
+ wc = LC_SMIT_TIMEOUT * 1024 * 1024;
- ct_cr_write_1(bst, bsh, wd3s_ctrl, ct->sc_creg | CR_DMA);
- bshw_lc_smit_start(ct, sp->scp_datalen, sp->scp_direction);
+ ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA);
+ bshw_lc_smit_start(ct, datalen, sp->scp_direction);
if (sp->scp_direction == SCSI_LOW_READ)
{
@@ -339,14 +372,14 @@ bshw_smit_xfer_start(ct)
break;
count = (datalen > LC_FSZ ? LC_FSZ : datalen);
- bus_space_read_region_4(ct->sc_memt, ct->sc_memh,
+ bus_space_read_region_4(chp->ch_memt, chp->ch_memh,
LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2);
data += count;
datalen -= count;
}
while (datalen > 0);
- bs->sc_tdatalen = datalen;
+ bs->sc_edatalen = datalen;
}
else
{
@@ -365,7 +398,7 @@ bshw_smit_xfer_start(ct)
}
count = (datalen > LC_SFSZ ? LC_SFSZ : datalen);
- bus_space_write_region_4(ct->sc_memt, ct->sc_memh,
+ bus_space_write_region_4(chp->ch_memt, chp->ch_memh,
LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2);
data += count;
datalen -= count;
@@ -374,7 +407,7 @@ bshw_smit_xfer_start(ct)
break;
count = (datalen > LC_REST ? LC_REST : datalen);
- bus_space_write_region_4(ct->sc_memt, ct->sc_memh,
+ bus_space_write_region_4(chp->ch_memt, chp->ch_memh,
LC_SMIT_OFFSET + LC_SFSZ,
(u_int32_t *) data, count >> 2);
data += count;
@@ -382,26 +415,33 @@ bshw_smit_xfer_start(ct)
}
while (datalen > 0);
}
+ return 0;
}
/*********************************************************
* DMA TRANSFER (BS)
*********************************************************/
+static __inline void bshw_dma_write_1 \
+ __P((struct ct_bus_access_handle *, bus_addr_t, u_int8_t));
static void bshw_dmastart __P((struct ct_softc *));
static void bshw_dmadone __P((struct ct_softc *));
-void
+int
bshw_dma_xfer_start(ct)
struct ct_softc *ct;
{
struct scsi_low_softc *slp = &ct->sc_sclow;
struct sc_p *sp = &slp->sl_scp;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
struct bshw_softc *bs = ct->ct_hw;
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
vaddr_t va, endva, phys, nphys;
+ u_int io_control;
+
+ io_control = bs->sc_io_control | bshw_io_control;
+ if ((io_control & BSHW_DMA_BLOCK) != 0 && sp->scp_datalen < 256)
+ return EINVAL;
- ct_cr_write_1(bst, bsh, wd3s_ctrl, ct->sc_creg | CR_DMA);
+ ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA);
phys = vtophys((vaddr_t) sp->scp_data);
if (phys >= bs->sc_minphys)
{
@@ -421,19 +461,17 @@ bshw_dma_xfer_start(ct)
/* setup segaddr */
bs->sc_segaddr = (u_int8_t *) phys;
/* setup seglen */
- endva = (vaddr_t)round_page((vaddr_t)(sp->scp_data +
- sp->scp_datalen));
+ endva = (vaddr_t) round_page((vaddr_t) sp->scp_data + sp->scp_datalen);
for (va = (vaddr_t) sp->scp_data; ; phys = nphys)
{
- if ((va += PAGE_SIZE) >= endva)
+ if ((va += BSHW_PAGE_SIZE) >= endva)
{
bs->sc_seglen = sp->scp_datalen;
break;
}
nphys = vtophys(va);
- if (phys + PAGE_SIZE != nphys ||
- nphys >= bs->sc_minphys)
+ if (phys + BSHW_PAGE_SIZE != nphys || nphys >= bs->sc_minphys)
{
bs->sc_seglen =
(u_int8_t *) trunc_page(va) - sp->scp_data;
@@ -445,7 +483,9 @@ bshw_dma_xfer_start(ct)
}
bshw_dmastart(ct);
- cthw_set_count(bst, bsh, bs->sc_seglen);
+ cthw_set_count(chp, bs->sc_seglen);
+ ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO);
+ return 0;
}
void
@@ -460,13 +500,13 @@ bshw_dma_xfer_stop(ct)
bshw_dmadone(ct);
- ti = slp->sl_nexus;
+ ti = slp->sl_Tnexus;
if (ti == NULL)
return;
if (ti->ti_phase == PH_DATA)
{
- count = cthw_get_count(ct->sc_iot, ct->sc_ioh);
+ count = cthw_get_count(&ct->sc_ch);
if (count < (u_int) bs->sc_seglen)
{
transbytes = bs->sc_seglen - count;
@@ -474,31 +514,27 @@ bshw_dma_xfer_stop(ct)
sp->scp_direction == SCSI_LOW_READ)
bcopy(bs->sc_bufp, sp->scp_data, transbytes);
- bs->sc_bufp = NULL;
sp->scp_data += transbytes;
sp->scp_datalen -= transbytes;
- return;
}
- else if (count == (u_int) bs->sc_seglen)
+ else if (count > (u_int) bs->sc_seglen)
{
- bs->sc_bufp = NULL;
- return;
+ printf("%s: port data %x != seglen %x\n",
+ slp->sl_xname, count, bs->sc_seglen);
+ slp->sl_error |= PDMAERR;
}
- printf("%s: port data %x != seglen %x\n",
- slp->sl_xname, count, bs->sc_seglen);
+ scsi_low_data_finish(slp);
}
else
{
printf("%s: extra DMA interrupt\n", slp->sl_xname);
+ slp->sl_error |= PDMAERR;
}
- slp->sl_error |= PDMAERR;
bs->sc_bufp = NULL;
}
-static int dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 };
-
/* common dma settings */
#undef DMA1_SMSK
#define DMA1_SMSK (0x15)
@@ -514,56 +550,64 @@ static int dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 };
#define DMA37MD_READ 0x08
#define DMA37MD_SINGLE 0x40
+static bus_addr_t dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 };
+
+static __inline void
+bshw_dma_write_1(chp, port, val)
+ struct ct_bus_access_handle *chp;
+ bus_addr_t port;
+ u_int8_t val;
+{
+
+ CT_BUS_WEIGHT(chp);
+ outb(port, val);
+}
+
static void
bshw_dmastart(ct)
struct ct_softc *ct;
{
struct scsi_low_softc *slp = &ct->sc_sclow;
struct bshw_softc *bs = ct->ct_hw;
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
int chan = bs->sc_drq;
- int waport;
- u_int8_t *phys = bs->sc_segaddr;
+ bus_addr_t waport;
+ u_int8_t regv, *phys = bs->sc_segaddr;
u_int nbytes = bs->sc_seglen;
+ /* flush cpu cache */
+ (*bs->sc_dmasync_before) (ct);
+
/*
* Program one of DMA channels 0..3. These are
* byte mode channels.
*/
/* set dma channel mode, and reset address ff */
-#ifdef __FreeBSD__
- if (need_pre_dma_flush)
- wbinvd();
-#else
- if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
- cpu_cf_preRead(curcpu);
- else
- cpu_cf_preWrite(curcpu);
-#endif
if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
- outb(DMA1_MODE, DMA37MD_SINGLE | DMA37MD_WRITE | chan);
+ regv = DMA37MD_WRITE | DMA37MD_SINGLE | chan;
else
- outb(DMA1_MODE, DMA37MD_SINGLE | DMA37MD_READ | chan);
- outb(DMA1_FFC, 0);
+ regv = DMA37MD_READ | DMA37MD_SINGLE | chan;
+
+ bshw_dma_write_1(chp, DMA1_MODE, regv);
+ bshw_dma_write_1(chp, DMA1_FFC, 0);
/* send start address */
waport = DMA1_CHN(chan);
- outb(waport, (u_int) phys);
- outb(waport, ((u_int) phys) >> 8);
- outb(dmapageport[chan], ((u_int) phys) >> 16);
+ bshw_dma_write_1(chp, waport, (u_int) phys);
+ bshw_dma_write_1(chp, waport, ((u_int) phys) >> 8);
+ bshw_dma_write_1(chp, dmapageport[chan], ((u_int) phys) >> 16);
/* send count */
- outb(waport + 2, --nbytes);
- outb(waport + 2, nbytes >> 8);
+ bshw_dma_write_1(chp, waport + 2, --nbytes);
+ bshw_dma_write_1(chp, waport + 2, nbytes >> 8);
/* vendor unique hook */
- if (bs->sc_hw->dma_start)
- (*bs->sc_hw->dma_start)(ct);
+ if (bs->sc_hw->hw_dma_start)
+ (*bs->sc_hw->hw_dma_start)(ct);
- outb(DMA1_SMSK, chan);
- bus_space_write_1(bst, bsh, cmd_port, CMDP_DMES);
+ bshw_dma_write_1(chp, DMA1_SMSK, chan);
+ ct_cmdp_write_1(chp, CMDP_DMES);
}
static void
@@ -571,25 +615,17 @@ bshw_dmadone(ct)
struct ct_softc *ct;
{
struct bshw_softc *bs = ct->ct_hw;
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
- outb(DMA1_SMSK, (bs->sc_drq | DMA37SM_SET));
- bus_space_write_1(bst, bsh, cmd_port, CMDP_DMER);
+ bshw_dma_write_1(chp, DMA1_SMSK, (bs->sc_drq | DMA37SM_SET));
+ ct_cmdp_write_1(chp, CMDP_DMER);
/* vendor unique hook */
- if (bs->sc_hw->dma_stop)
- (*bs->sc_hw->dma_stop)(ct);
+ if (bs->sc_hw->hw_dma_stop)
+ (*bs->sc_hw->hw_dma_stop) (ct);
-#ifdef __FreeBSD__
- if (need_post_dma_flush)
- invd();
-#else
- if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
- cpu_cf_postRead(curcpu);
- else
- cpu_cf_postWrite(curcpu);
-#endif
+ /* flush cpu cache */
+ (*bs->sc_dmasync_after) (ct);
}
/**********************************************
@@ -606,16 +642,15 @@ static int
bshw_dma_init_texa(ct)
struct ct_softc *ct;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
u_int8_t regval;
- if ((regval = ct_cr_read_1(bst, bsh, 0x37)) & 0x08)
+ if ((regval = ct_cr_read_1(chp, 0x37)) & 0x08)
return 0;
- ct_cr_write_1(bst, bsh, 0x37, regval | 0x08);
- regval = ct_cr_read_1(bst, bsh, 0x3f);
- ct_cr_write_1(bst, bsh, 0x3f, regval | 0x08);
+ ct_cr_write_1(chp, 0x37, regval | 0x08);
+ regval = ct_cr_read_1(chp, 0x3f);
+ ct_cr_write_1(chp, 0x3f, regval | 0x08);
return 1;
}
@@ -623,26 +658,25 @@ static int
bshw_dma_init_sc98(ct)
struct ct_softc *ct;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
- if (ct_cr_read_1(bst, bsh, 0x37) & 0x08)
+ if (ct_cr_read_1(chp, 0x37) & 0x08)
return 0;
/* If your card is SC98 with bios ver 1.01 or 1.02 under no PCI */
- ct_cr_write_1(bst, bsh, 0x37, 0x1a);
- ct_cr_write_1(bst, bsh, 0x3f, 0x1a);
+ ct_cr_write_1(chp, 0x37, 0x1a);
+ ct_cr_write_1(chp, 0x3f, 0x1a);
#if 0
/* only valid for IO */
- ct_cr_write_1(bst, bsh, 0x40, 0xf4);
- ct_cr_write_1(bst, bsh, 0x41, 0x9);
- ct_cr_write_1(bst, bsh, 0x43, 0xff);
- ct_cr_write_1(bst, bsh, 0x46, 0x4e);
-
- ct_cr_write_1(bst, bsh, 0x48, 0xf4);
- ct_cr_write_1(bst, bsh, 0x49, 0x9);
- ct_cr_write_1(bst, bsh, 0x4b, 0xff);
- ct_cr_write_1(bst, bsh, 0x4e, 0x4e);
+ ct_cr_write_1(chp, 0x40, 0xf4);
+ ct_cr_write_1(chp, 0x41, 0x9);
+ ct_cr_write_1(chp, 0x43, 0xff);
+ ct_cr_write_1(chp, 0x46, 0x4e);
+
+ ct_cr_write_1(chp, 0x48, 0xf4);
+ ct_cr_write_1(chp, 0x49, 0x9);
+ ct_cr_write_1(chp, 0x4b, 0xff);
+ ct_cr_write_1(chp, 0x4e, 0x4e);
#endif
return 1;
}
@@ -651,44 +685,40 @@ static void
bshw_dma_start_sc98(ct)
struct ct_softc *ct;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
- ct_cr_write_1(bst, bsh, 0x73, 0x32);
- ct_cr_write_1(bst, bsh, 0x74, 0x23);
+ ct_cr_write_1(chp, 0x73, 0x32);
+ ct_cr_write_1(chp, 0x74, 0x23);
}
static void
bshw_dma_stop_sc98(ct)
struct ct_softc *ct;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
- ct_cr_write_1(bst, bsh, 0x73, 0x43);
- ct_cr_write_1(bst, bsh, 0x74, 0x34);
+ ct_cr_write_1(chp, 0x73, 0x43);
+ ct_cr_write_1(chp, 0x74, 0x34);
}
static void
bshw_dma_start_elecom(ct)
struct ct_softc *ct;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
- u_int8_t tmp = ct_cr_read_1(bst, bsh, 0x4c);
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
+ u_int8_t tmp = ct_cr_read_1(chp, 0x4c);
- ct_cr_write_1(bst, bsh, 0x32, tmp & 0xdf);
+ ct_cr_write_1(chp, 0x32, tmp & 0xdf);
}
static void
bshw_dma_stop_elecom(ct)
struct ct_softc *ct;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
- u_int8_t tmp = ct_cr_read_1(bst, bsh, 0x4c);
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
+ u_int8_t tmp = ct_cr_read_1(chp, 0x4c);
- ct_cr_write_1(bst, bsh, 0x32, tmp | 0x20);
+ ct_cr_write_1(chp, 0x32, tmp | 0x20);
}
static struct bshw bshw_generic = {
diff --git a/sys/dev/ct/bshwvar.h b/sys/dev/ct/bshwvar.h
index 6e31b4d..17268f0 100644
--- a/sys/dev/ct/bshwvar.h
+++ b/sys/dev/ct/bshwvar.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $NecBSD: bshwvar.h,v 1.3 1999/04/15 01:36:10 kmatsuda Exp $ */
+/* $NecBSD: bshwvar.h,v 1.3.14.3 2001/06/21 04:07:37 honda Exp $ */
/* $NetBSD$ */
/*
@@ -46,12 +46,11 @@ struct bshw {
#define BSHW_SMFIFO 0x02
#define BSHW_DOUBLE_DMACHAN 0x04
u_int hw_flags;
+ u_int hw_sregaddr;
- u_int sregaddr;
-
- int ((*dma_init) __P((struct ct_softc *)));
- void ((*dma_start) __P((struct ct_softc *)));
- void ((*dma_stop) __P((struct ct_softc *)));
+ int ((*hw_dma_init) __P((struct ct_softc *)));
+ void ((*hw_dma_start) __P((struct ct_softc *)));
+ void ((*hw_dma_stop) __P((struct ct_softc *)));
};
struct bshw_softc {
@@ -63,7 +62,8 @@ struct bshw_softc {
u_int8_t *sc_segaddr;
u_int8_t *sc_bufp;
int sc_seglen;
- int sc_tdatalen; /* temp datalen */
+ u_int sc_sdatalen; /* SMIT */
+ u_int sc_edatalen; /* SMIT */
/* private bounce */
u_int8_t *sc_bounce_phys;
@@ -71,16 +71,26 @@ struct bshw_softc {
u_int sc_bounce_size;
bus_addr_t sc_minphys;
+ /* io control */
+#define BSHW_READ_INTERRUPT_DRIVEN 0x0001
+#define BSHW_WRITE_INTERRUPT_DRIVEN 0x0002
+#define BSHW_DMA_BLOCK 0x0010
+#define BSHW_SMIT_BLOCK 0x0020
+ u_int sc_io_control;
+
/* hardware */
struct bshw *sc_hw;
+ void ((*sc_dmasync_before)) __P((struct ct_softc *));
+ void ((*sc_dmasync_after)) __P((struct ct_softc *));
};
-void bshw_synch_setup __P((struct ct_softc *, struct lun_info *));
+void bshw_synch_setup __P((struct ct_softc *, struct targ_info *));
void bshw_bus_reset __P((struct ct_softc *));
-int bshw_read_settings __P((bus_space_tag_t, bus_space_handle_t, struct bshw_softc *));
-void bshw_smit_xfer_start __P((struct ct_softc *));
+int bshw_read_settings __P((struct ct_bus_access_handle *, struct bshw_softc *));
+int bshw_smit_xfer_start __P((struct ct_softc *));
void bshw_smit_xfer_stop __P((struct ct_softc *));
-void bshw_dma_xfer_start __P((struct ct_softc *));
+int bshw_dma_xfer_start __P((struct ct_softc *));
void bshw_dma_xfer_stop __P((struct ct_softc *));
+
extern struct dvcfg_hwsel bshw_hwsel;
#endif /* !_BSHWVAR_H_ */
diff --git a/sys/dev/ct/ct.c b/sys/dev/ct/ct.c
index f2fe883a..6c46493 100644
--- a/sys/dev/ct/ct.c
+++ b/sys/dev/ct/ct.c
@@ -1,16 +1,16 @@
/* $FreeBSD$ */
-/* $NecBSD: ct.c,v 1.13 1999/07/23 20:54:00 honda Exp $ */
+/* $NecBSD: ct.c,v 1.13.12.5 2001/06/26 07:31:53 honda Exp $ */
/* $NetBSD$ */
#define CT_DEBUG
-#define CT_USE_CCSEQ
+#define CT_IO_CONTROL_FLAGS (CT_USE_CCSEQ | CT_FAST_INTR)
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999
+ * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
*
- * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999
+ * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
* Naofumi HONDA. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,17 +42,17 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/disklabel.h>
+#if defined(__FreeBSD__) && __FreeBSD_version > 500001
#include <sys/bio.h>
+#endif /* __ FreeBSD__ */
#include <sys/buf.h>
#include <sys/queue.h>
#include <sys/malloc.h>
-#include <sys/device_port.h>
#include <sys/errno.h>
-#include <vm/vm.h>
-
#ifdef __NetBSD__
+#include <sys/device.h>
+
#include <machine/bus.h>
#include <machine/intr.h>
@@ -68,6 +68,7 @@
#include <dev/ic/wd33c93reg.h>
#include <i386/Cbus/dev/ct/ctvar.h>
+#include <i386/Cbus/dev/ct/ct_machdep.h>
#endif /* __NetBSD__ */
#ifdef __FreeBSD__
@@ -80,28 +81,31 @@
#include <dev/ic/wd33c93reg.h>
#include <dev/ct/ctvar.h>
+#include <dev/ct/ct_machdep.h>
#endif /* __FreeBSD__ */
+#define CT_NTARGETS 8
+#define CT_NLUNS 8
+#define CT_RESET_DEFAULT 2000
+#define CT_DELAY_MAX (2 * 1000 * 1000)
+#define CT_DELAY_INTERVAL (1)
+
/***************************************************
* DEBUG
***************************************************/
-#define CT_NTARGETS 8
-#define CT_NLUNS 8
-#define CT_RESET_DEFAULT 2000
-
-#ifndef DDB
-#define Debugger() panic("should call debugger here (ct.c)")
-#else /* ! DDB */
-#ifdef __FreeBSD__
-#define Debugger() Debugger("ct")
-#endif /* __FreeBSD__ */
-#endif
-
#ifdef CT_DEBUG
int ct_debug;
#endif /* CT_DEBUG */
/***************************************************
+ * IO control
+ ***************************************************/
+#define CT_USE_CCSEQ 0x0100
+#define CT_FAST_INTR 0x0200
+
+u_int ct_io_control = CT_IO_CONTROL_FLAGS;
+
+/***************************************************
* default data
***************************************************/
u_int8_t cthw_cmdlevel[256] = {
@@ -124,44 +128,61 @@ u_int8_t cthw_cmdlevel[256] = {
/*F*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
};
+#if 0
/* default synch data table */
/* A 10 6.6 5.0 4.0 3.3 2.8 2.5 2.0 M/s */
/* X 100 150 200 250 300 350 400 500 ns */
-static struct ct_synch_data ct_synch_data_20MHz[] = {
+static struct ct_synch_data ct_synch_data_FSCSI[] = {
{25, 0xa0}, {37, 0xb0}, {50, 0x20}, {62, 0xd0}, {75, 0x30},
{87, 0xf0}, {100, 0x40}, {125, 0x50}, {0, 0}
};
-extern unsigned int delaycount;
+static struct ct_synch_data ct_synch_data_SCSI[] = {
+ {50, 0x20}, {75, 0x30}, {100, 0x40}, {125, 0x50}, {0, 0}
+};
+#endif
+/***************************************************
+ * DEVICE STRUCTURE
+ ***************************************************/
+extern struct cfdriver ct_cd;
/*****************************************************************
* Interface functions
*****************************************************************/
-static int ct_xfer __P((struct ct_softc *, u_int8_t *, int, int));
+static int ct_xfer __P((struct ct_softc *, u_int8_t *, int, int, u_int *));
static void ct_io_xfer __P((struct ct_softc *));
-static __inline int ct_reselected __P((struct ct_softc *));
+static int ct_reselected __P((struct ct_softc *, u_int8_t));
static void ct_phase_error __P((struct ct_softc *, u_int8_t));
static int ct_start_selection __P((struct ct_softc *, struct slccb *));
static int ct_msg __P((struct ct_softc *, struct targ_info *, u_int));
static int ct_world_start __P((struct ct_softc *, int));
static __inline void cthw_phase_bypass __P((struct ct_softc *, u_int8_t));
-static int cthw_chip_reset __P((bus_space_tag_t, bus_space_handle_t, int, int));
+static int cthw_chip_reset __P((struct ct_bus_access_handle *, int *, int, int));
static void cthw_bus_reset __P((struct ct_softc *));
-static int ct_nexus __P((struct ct_softc *, struct targ_info *));
+static int ct_ccb_nexus_establish __P((struct ct_softc *));
+static int ct_lun_nexus_establish __P((struct ct_softc *));
+static int ct_target_nexus_establish __P((struct ct_softc *, int, int));
static void cthw_attention __P((struct ct_softc *));
-static int ct_targ_init __P((struct ct_softc *, struct targ_info *));
+static int ct_targ_init __P((struct ct_softc *, struct targ_info *, int));
+static int ct_unbusy __P((struct ct_softc *));
+static void ct_attention __P((struct ct_softc *));
+static struct ct_synch_data *ct_make_synch_table __P((struct ct_softc *));
+static int ct_catch_intr __P((struct ct_softc *));
struct scsi_low_funcs ct_funcs = {
SC_LOW_INIT_T ct_world_start,
SC_LOW_BUSRST_T cthw_bus_reset,
SC_LOW_TARG_INIT_T ct_targ_init,
+ SC_LOW_LUN_INIT_T NULL,
SC_LOW_SELECT_T ct_start_selection,
- SC_LOW_NEXUS_T ct_nexus,
+ SC_LOW_NEXUS_T ct_lun_nexus_establish,
+ SC_LOW_NEXUS_T ct_ccb_nexus_establish,
SC_LOW_ATTEN_T cthw_attention,
SC_LOW_MSG_T ct_msg,
+ SC_LOW_TIMEOUT_T NULL,
SC_LOW_POLL_T ctintr,
NULL, /* SC_LOW_POWER_T cthw_power, */
@@ -175,12 +196,10 @@ cthw_phase_bypass(ct, ph)
struct ct_softc *ct;
u_int8_t ph;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
- ct_cr_write_1(bst, bsh, wd3s_cph, ph);
- ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_SELECT_ATN_TFR);
- ct->sc_satgo = CT_SAT_GOING;
+ ct_cr_write_1(chp, wd3s_cph, ph);
+ ct_cr_write_1(chp, wd3s_cmd, WD3S_SELECT_ATN_TFR);
}
static void
@@ -196,9 +215,9 @@ cthw_bus_reset(ct)
}
static int
-cthw_chip_reset(bst, bsh, chipclk, hostid)
- bus_space_tag_t bst;
- bus_space_handle_t bsh;
+cthw_chip_reset(chp, chiprevp, chipclk, hostid)
+ struct ct_bus_access_handle *chp;
+ int *chiprevp;
int chipclk, hostid;
{
#define CT_SELTIMEOUT_20MHz_REGV (0x80)
@@ -207,26 +226,29 @@ cthw_chip_reset(bst, bsh, chipclk, hostid)
int wc;
/* issue abort cmd */
- ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_ABORT);
- delay(1000); /* 1ms wait */
- (void) ct_stat_read_1(bst, bsh);
- (void) ct_cr_read_1(bst, bsh, wd3s_stat);
+ ct_cr_write_1(chp, wd3s_cmd, WD3S_ABORT);
+ SCSI_LOW_DELAY(1000); /* 1ms wait */
+ (void) ct_stat_read_1(chp);
+ (void) ct_cr_read_1(chp, wd3s_stat);
/* setup chip registers */
regv = 0;
seltout = CT_SELTIMEOUT_20MHz_REGV;
switch (chipclk)
{
+ case 8:
case 10:
seltout = (seltout * chipclk) / 20;
- regv = 0;
+ regv = IDR_FS_8_10;
break;
+ case 12:
case 15:
seltout = (seltout * chipclk) / 20;
regv = IDR_FS_12_15;
break;
+ case 16:
case 20:
seltout = (seltout * chipclk) / 20;
regv = IDR_FS_16_20;
@@ -236,51 +258,117 @@ cthw_chip_reset(bst, bsh, chipclk, hostid)
panic("ct: illegal chip clk rate\n");
break;
}
- regv |= IDR_EHP | hostid;
- ct_cr_write_1(bst, bsh, wd3s_oid, regv);
- ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_RESET);
+ regv |= IDR_EHP | hostid | IDR_RAF | IDR_EAF;
+ ct_cr_write_1(chp, wd3s_oid, regv);
+
+ ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET);
for (wc = CT_RESET_DEFAULT; wc > 0; wc --)
{
- aux = ct_stat_read_1(bst, bsh);
+ aux = ct_stat_read_1(chp);
if (aux != 0xff && (aux & STR_INT))
{
- if (ct_cr_read_1(bst, bsh, wd3s_stat) == 0)
+ regv = ct_cr_read_1(chp, wd3s_stat);
+ if (regv == BSR_RESET || regv == BSR_AFM_RESET)
break;
- ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_RESET);
+ ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET);
}
- delay(1);
+ SCSI_LOW_DELAY(1);
}
if (wc == 0)
return ENXIO;
- ct_cr_write_1(bst, bsh, wd3s_tout, seltout);
- ct_cr_write_1(bst, bsh, wd3s_sid, SIDR_RESEL);
- ct_cr_write_1(bst, bsh, wd3s_ctrl, CR_DEFAULT);
- ct_cr_write_1(bst, bsh, wd3s_synch, 0);
+ ct_cr_write_1(chp, wd3s_tout, seltout);
+ ct_cr_write_1(chp, wd3s_sid, SIDR_RESEL);
+ ct_cr_write_1(chp, wd3s_ctrl, CR_DEFAULT);
+ ct_cr_write_1(chp, wd3s_synch, 0);
+ if (chiprevp != NULL)
+ {
+ *chiprevp = CT_WD33C93;
+ if (regv == BSR_RESET)
+ goto out;
+
+ *chiprevp = CT_WD33C93_A;
+ ct_cr_write_1(chp, wd3s_qtag, 0xaa);
+ if (ct_cr_read_1(chp, wd3s_qtag) != 0xaa)
+ {
+ ct_cr_write_1(chp, wd3s_qtag, 0x0);
+ goto out;
+ }
+ ct_cr_write_1(chp, wd3s_qtag, 0x55);
+ if (ct_cr_read_1(chp, wd3s_qtag) != 0x55)
+ {
+ ct_cr_write_1(chp, wd3s_qtag, 0x0);
+ goto out;
+ }
+ ct_cr_write_1(chp, wd3s_qtag, 0x0);
+ *chiprevp = CT_WD33C93_B;
+ }
- (void) ct_stat_read_1(bst, bsh);
- (void) ct_cr_read_1(bst, bsh, wd3s_stat);
+out:
+ (void) ct_stat_read_1(chp);
+ (void) ct_cr_read_1(chp, wd3s_stat);
return 0;
}
+static struct ct_synch_data *
+ct_make_synch_table(ct)
+ struct ct_softc *ct;
+{
+ struct ct_synch_data *sdtp, *sdp;
+ u_int base, i, period;
+
+ sdtp = sdp = &ct->sc_default_sdt[0];
+
+ if ((ct->sc_chipclk % 5) == 0)
+ base = 1000 / (5 * 2); /* 5 MHz type */
+ else
+ base = 1000 / (4 * 2); /* 4 MHz type */
+
+ if (ct->sc_chiprev >= CT_WD33C93_B)
+ {
+ /* fast scsi */
+ for (i = 2; i < 8; i ++, sdp ++)
+ {
+ period = (base * i) / 2;
+ if (period >= 200) /* 5 MHz */
+ break;
+ sdp->cs_period = period / 4;
+ sdp->cs_syncr = (i * 0x10) | 0x80;
+ }
+ }
+
+ for (i = 2; i < 8; i ++, sdp ++)
+ {
+ period = (base * i);
+ if (period > 500) /* 2 MHz */
+ break;
+ sdp->cs_period = period / 4;
+ sdp->cs_syncr = (i * 0x10);
+ }
+
+ sdp->cs_period = 0;
+ sdp->cs_syncr = 0;
+ return sdtp;
+}
+
/**************************************************
* Attach & Probe
**************************************************/
int
-ctprobesubr(bst, bsh, dvcfg, hsid, chipclk)
- bus_space_tag_t bst;
- bus_space_handle_t bsh;
+ctprobesubr(chp, dvcfg, hsid, chipclk, chiprevp)
+ struct ct_bus_access_handle *chp;
u_int dvcfg, chipclk;
int hsid;
+ int *chiprevp;
{
#if 0
- if ((ct_stat_read_1(bst, bsh) & STR_BUSY) != 0)
+ if ((ct_stat_read_1(chp) & STR_BSY) != 0)
return 0;
#endif
- if (cthw_chip_reset(bst, bsh, chipclk, hsid) != 0)
+ if (cthw_chip_reset(chp, chiprevp, chipclk, hsid) != 0)
return 0;
return 1;
}
@@ -302,10 +390,11 @@ ctattachsubr(ct)
{
struct scsi_low_softc *slp = &ct->sc_sclow;
- ct->sc_wc = delaycount * 2000; /* 2 sec */
+ ct->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
slp->sl_funcs = &ct_funcs;
- (void) scsi_low_attach(slp, 2, CT_NTARGETS, CT_NLUNS,
- sizeof(struct ct_targ_info));
+ slp->sl_flags |= HW_READ_PADDING;
+ (void) scsi_low_attach(slp, 0, CT_NTARGETS, CT_NLUNS,
+ sizeof(struct ct_targ_info), 0);
}
/**************************************************
@@ -315,44 +404,75 @@ static void
cthw_attention(ct)
struct ct_softc *ct;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
- if ((ct_stat_read_1(bst, bsh) & STR_BUSY) != 0)
- {
- ct->sc_atten = 1;
+ ct->sc_atten = 1;
+ if ((ct_stat_read_1(chp) & (STR_BSY | STR_CIP)) != 0)
return;
- }
- ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_ASSERT_ATN);
- delay(10);
- if ((ct_stat_read_1(bst, bsh) & STR_LCI) != 0)
+ ct_cr_write_1(chp, wd3s_cmd, WD3S_ASSERT_ATN);
+ SCSI_LOW_DELAY(10);
+ if ((ct_stat_read_1(chp) & STR_LCI) == 0)
+ ct->sc_atten = 0;
+ ct_unbusy(ct);
+ return;
+}
+
+static void
+ct_attention(ct)
+ struct ct_softc *ct;
+{
+ struct scsi_low_softc *slp = &ct->sc_sclow;
+
+ if (slp->sl_atten == 0)
{
- ct->sc_atten = 1;
- return;
+ ct_unbusy(ct);
+ scsi_low_attention(slp);
+ }
+ else if (ct->sc_atten != 0)
+ {
+ ct_unbusy(ct);
+ cthw_attention(ct);
}
- ct->sc_atten = 0;
}
static int
-ct_targ_init(ct, ti)
+ct_targ_init(ct, ti, action)
struct ct_softc *ct;
struct targ_info *ti;
+ int action;
{
struct ct_targ_info *cti = (void *) ti;
- if (ct->sc_chiprev == CT_WD33C93_A)
+ if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
{
- ti->ti_maxsynch.period = 200 / 4; /* 5MHz */
- ti->ti_maxsynch.offset = 8;
- }
- else
- {
- ti->ti_maxsynch.period = 100 / 4; /* 10MHz */
- ti->ti_maxsynch.offset = 12;
+ if (ct->sc_sdp == NULL)
+ {
+ ct->sc_sdp = ct_make_synch_table(ct);
+ }
+
+ switch (ct->sc_chiprev)
+ {
+ default:
+ ti->ti_maxsynch.offset = 5;
+ break;
+
+ case CT_WD33C93_A:
+ case CT_AM33C93_A:
+ ti->ti_maxsynch.offset = 12;
+ break;
+
+ case CT_WD33C93_B:
+ case CT_WD33C93_C:
+ ti->ti_maxsynch.offset = 12;
+ break;
+ }
+
+ ti->ti_maxsynch.period = ct->sc_sdp[0].cs_period;
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
+ cti->cti_syncreg = 0;
}
- cti->cti_syncreg = 0;
return 0;
}
@@ -362,14 +482,13 @@ ct_world_start(ct, fdone)
int fdone;
{
struct scsi_low_softc *slp = &ct->sc_sclow;
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
- intrmask_t s;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
if (ct->sc_sdp == NULL)
- ct->sc_sdp = &ct_synch_data_20MHz[0];
+ {
+ ct->sc_sdp = ct_make_synch_table(ct);
+ }
- slp->sl_cfgflags |= CFG_MSGUNIFY;
if (slp->sl_cfgflags & CFG_NOPARITY)
ct->sc_creg = CR_DEFAULT;
else
@@ -382,11 +501,9 @@ ct_world_start(ct, fdone)
ct->sc_dma = 0;
ct->sc_atten = 0;
- s = splcam();
- cthw_chip_reset(bst, bsh, ct->sc_chipclk, slp->sl_hostid);
+ cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid);
scsi_low_bus_reset(slp);
- cthw_chip_reset(bst, bsh, ct->sc_chipclk, slp->sl_hostid);
- splx(s);
+ cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid);
SOFT_INTR_REQUIRED(slp);
return 0;
@@ -398,25 +515,29 @@ ct_start_selection(ct, cb)
struct slccb *cb;
{
struct scsi_low_softc *slp = &ct->sc_sclow;
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
- struct targ_info *ti = slp->sl_nexus;
- struct lun_info *li = ti->ti_li;
- int s;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
+
+ struct targ_info *ti = slp->sl_Tnexus;
+ struct lun_info *li = slp->sl_Lnexus;
+ int s, satok;
u_int8_t cmd;
+ ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
ct->sc_atten = 0;
- if (cthw_cmdlevel[slp->sl_scp.scp_cmd[0]] != 0)
+ satok = 0;
+
+ if (scsi_low_is_disconnect_ok(cb) != 0)
+ {
+ if (ct->sc_chiprev >= CT_WD33C93_A)
+ satok = 1;
+ else if (cthw_cmdlevel[slp->sl_scp.scp_cmd[0]] != 0)
+ satok = 1;
+ }
+
+ if (satok != 0 &&
+ scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0)
{
- /*
- * This completely violates scsi protocols,
- * however some old devices do not work
- * properly with scsi attentions.
- */
- if ((li->li_flags & SCSI_LOW_DISC) != 0)
- cmd = WD3S_SELECT_ATN_TFR;
- else
- cmd = WD3S_SELECT_NO_ATN_TFR;
+ cmd = WD3S_SELECT_ATN_TFR;
ct->sc_satgo = CT_SAT_GOING;
}
else
@@ -425,24 +546,33 @@ ct_start_selection(ct, cb)
ct->sc_satgo = 0;
}
- if ((ct_stat_read_1(bst, bsh) & STR_BUSY) != 0)
+ if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) != 0)
return SCSI_LOW_START_FAIL;
- scsi_low_cmd(slp, ti);
-
if ((ct->sc_satgo & CT_SAT_GOING) != 0)
- ct_write_cmds(bst, bsh,
- slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
+ {
+ (void) scsi_low_msgout(slp, ti, SCSI_LOW_MSGOUT_INIT);
+ scsi_low_cmd(slp, ti);
+ ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen);
+ ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
+ }
+ else
+ {
+ /* anyway attention assert */
+ SCSI_LOW_ASSERT_ATN(slp);
+ }
+
+ ct_target_nexus_establish(ct, li->li_lun, slp->sl_scp.scp_direction);
s = splhigh();
- if ((ct_stat_read_1(bst, bsh) & STR_BUSY) == 0)
+ if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) == 0)
{
/* XXX:
* Reload a lun again here.
*/
- ct_cr_write_1(bst, bsh, wd3s_lun, li->li_lun);
- ct_cr_write_1(bst, bsh, wd3s_cmd, cmd);
- if ((ct_stat_read_1(bst, bsh) & STR_LCI) == 0)
+ ct_cr_write_1(chp, wd3s_lun, li->li_lun);
+ ct_cr_write_1(chp, wd3s_cmd, cmd);
+ if ((ct_stat_read_1(chp) & STR_LCI) == 0)
{
splx(s);
SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
@@ -459,12 +589,23 @@ ct_msg(ct, ti, msg)
struct targ_info *ti;
u_int msg;
{
- struct lun_info *li = ti->ti_li;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
struct ct_targ_info *cti = (void *) ti;
struct ct_synch_data *csp = ct->sc_sdp;
u_int offset, period;
+ int error;
+
+ if ((msg & SCSI_LOW_MSG_WIDE) != 0)
+ {
+ if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
+ {
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
+ return EINVAL;
+ }
+ return 0;
+ }
- if (msg != SCSI_LOW_MSG_SYNCH)
+ if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
return 0;
offset = ti->ti_maxsynch.offset;
@@ -480,95 +621,117 @@ ct_msg(ct, ti, msg)
ti->ti_maxsynch.period = 0;
ti->ti_maxsynch.offset = 0;
cti->cti_syncreg = 0;
- return EINVAL;
+ error = EINVAL;
+ }
+ else
+ {
+ cti->cti_syncreg = ((offset & 0x0f) | csp->cs_syncr);
+ error = 0;
}
- cti->cti_syncreg = ((offset & 0x0f) | csp->cs_syncr);
if (ct->ct_synch_setup != 0)
- (*ct->ct_synch_setup) (ct, li);
- return 0;
+ (*ct->ct_synch_setup) (ct, ti);
+ ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg);
+ return error;
}
/*************************************************
* <DATA PHASE>
*************************************************/
static int
-ct_xfer(ct, data, len, direction)
+ct_xfer(ct, data, len, direction, statp)
struct ct_softc *ct;
u_int8_t *data;
int len, direction;
+ u_int *statp;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
int wc;
register u_int8_t aux;
+ *statp = 0;
if (len == 1)
{
- ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_SBT | WD3S_TFR_INFO);
+ ct_cr_write_1(chp, wd3s_cmd, WD3S_SBT | WD3S_TFR_INFO);
}
else
{
- cthw_set_count(bst, bsh, len);
- ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_TFR_INFO);
+ cthw_set_count(chp, len);
+ ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO);
}
- aux = ct_stat_read_1(bst, bsh);
+ aux = ct_stat_read_1(chp);
if ((aux & STR_LCI) != 0)
{
- cthw_set_count(bst, bsh, 0);
+ cthw_set_count(chp, 0);
return len;
}
- for (wc = ct->sc_wc ; wc > 0; wc --)
+ for (wc = 0; wc < ct->sc_tmaxcnt; wc ++)
{
/* check data ready */
if ((aux & (STR_BSY | STR_DBR)) == (STR_BSY | STR_DBR))
{
if (direction == SCSI_LOW_READ)
- *data = ct_cr_read_1(bst, bsh, wd3s_data);
+ {
+ *data = ct_cr_read_1(chp, wd3s_data);
+ if ((aux & STR_PE) != 0)
+ *statp |= SCSI_LOW_DATA_PE;
+ }
else
- ct_cr_write_1(bst, bsh, wd3s_data, *data);
+ {
+ ct_cr_write_1(chp, wd3s_data, *data);
+ }
len --;
if (len <= 0)
break;
data ++;
}
+ else
+ {
+ SCSI_LOW_DELAY(1);
+ }
/* check phase miss */
- aux = ct_stat_read_1(bst, bsh);
+ aux = ct_stat_read_1(chp);
if ((aux & STR_INT) != 0)
break;
}
return len;
}
+#define CT_PADDING_BUF_SIZE 32
+
static void
ct_io_xfer(ct)
struct ct_softc *ct;
{
struct scsi_low_softc *slp = &ct->sc_sclow;
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
struct sc_p *sp = &slp->sl_scp;
- u_int dummy;
+ u_int stat;
int len;
+ u_int8_t pbuf[CT_PADDING_BUF_SIZE];
- /* io polling mode */
- ct_cr_write_1(bst, bsh, wd3s_ctrl, ct->sc_creg);
+ /* polling mode */
+ ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg);
if (sp->scp_datalen <= 0)
{
slp->sl_error |= PDMAERR;
- dummy = 0;
- len = ct_xfer(ct, (u_int8_t *) &dummy, 1, sp->scp_direction);
+
+ if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
+ SCSI_LOW_BZERO(pbuf, CT_PADDING_BUF_SIZE);
+ ct_xfer(ct, pbuf, CT_PADDING_BUF_SIZE,
+ sp->scp_direction, &stat);
}
else
+ {
len = ct_xfer(ct, sp->scp_data, sp->scp_datalen,
- sp->scp_direction);
-
- sp->scp_data += (sp->scp_datalen - len);
- sp->scp_datalen = len;
+ sp->scp_direction, &stat);
+ sp->scp_data += (sp->scp_datalen - len);
+ sp->scp_datalen = len;
+ }
}
/**************************************************
@@ -598,7 +761,7 @@ ct_phase_error(ct, scsi_status)
u_int8_t scsi_status;
{
struct scsi_low_softc *slp = &ct->sc_sclow;
- struct targ_info *ti = slp->sl_nexus;
+ struct targ_info *ti = slp->sl_Tnexus;
struct ct_err *pep;
u_int msg = 0;
@@ -618,13 +781,13 @@ ct_phase_error(ct, scsi_status)
msg = pep->pe_errmsg;
if (msg != 0)
- scsi_low_assert_msg(slp, slp->sl_nexus, msg, 1);
+ scsi_low_assert_msg(slp, slp->sl_Tnexus, msg, 1);
if (pep->pe_msg != NULL)
{
printf("%s: phase error: %s",
slp->sl_xname, pep->pe_msg);
- scsi_low_print(slp, slp->sl_nexus);
+ scsi_low_print(slp, slp->sl_Tnexus);
}
if (pep->pe_done != 0)
@@ -640,90 +803,193 @@ ct_phase_error(ct, scsi_status)
/**************************************************
* ### SCSI PHASE SEQUENCER ###
**************************************************/
-static __inline int
-ct_reselected(ct)
+static int
+ct_reselected(ct, scsi_status)
struct ct_softc *ct;
+ u_int8_t scsi_status;
{
struct scsi_low_softc *slp = &ct->sc_sclow;
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
struct targ_info *ti;
u_int sid;
+ u_int8_t regv;
ct->sc_atten = 0;
- sid = (ct_cr_read_1(bst, bsh, wd3s_sid) & SIDR_IDM);
+ ct->sc_satgo &= ~CT_SAT_GOING;
+ regv = ct_cr_read_1(chp, wd3s_sid);
+ if ((regv & SIDR_VALID) == 0)
+ return EJUSTRETURN;
+
+ sid = regv & SIDR_IDM;
if ((ti = scsi_low_reselected(slp, sid)) == NULL)
return EJUSTRETURN;
- ct_cr_write_1(bst, bsh, wd3s_did, sid);
- ct_cr_write_1(bst, bsh, wd3s_lun, 0); /* temp */
- ct_cr_write_1(bst, bsh, wd3s_ctrl, ct->sc_creg | CR_DMA);
- cthw_set_count(bst, bsh, 0);
+ ct_target_nexus_establish(ct, 0, SCSI_LOW_READ);
+ if (scsi_status != BSR_AFM_RESEL)
+ return EJUSTRETURN;
+
+ SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
+ regv = ct_cr_read_1(chp, wd3s_data);
+ if (scsi_low_msgin(slp, ti, (u_int) regv) == 0)
+ {
+ if (scsi_low_is_msgout_continue(ti, 0) != 0)
+ {
+ /* XXX: scsi_low_attetion */
+ scsi_low_attention(slp);
+ }
+ }
+
+ if (ct->sc_atten != 0)
+ {
+ ct_attention(ct);
+ }
+
+ ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK);
return EJUSTRETURN;
}
static int
-ct_nexus(ct, ti)
+ct_target_nexus_establish(ct, lun, dir)
struct ct_softc *ct;
- struct targ_info *ti;
+ int lun, dir;
{
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
- struct lun_info *li = ti->ti_li;
+ struct scsi_low_softc *slp = &ct->sc_sclow;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
+ struct targ_info *ti = slp->sl_Tnexus;
struct ct_targ_info *cti = (void *) ti;
- if ((li->li_flags & SCSI_LOW_NOPARITY) != 0)
- ct->sc_creg = CR_DEFAULT;
+ if (dir == SCSI_LOW_WRITE)
+ ct_cr_write_1(chp, wd3s_did, ti->ti_id);
else
- ct->sc_creg = CR_DEFAULT_HP;
+ ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD);
+ ct_cr_write_1(chp, wd3s_lun, lun);
+ ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA);
+ ct_cr_write_1(chp, wd3s_cph, 0);
+ ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg);
+ cthw_set_count(chp, 0);
+ return 0;
+}
+
+static int
+ct_lun_nexus_establish(ct)
+ struct ct_softc *ct;
+{
+ struct scsi_low_softc *slp = &ct->sc_sclow;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
+ struct lun_info *li = slp->sl_Lnexus;
+
+ ct_cr_write_1(chp, wd3s_lun, li->li_lun);
+ return 0;
+}
+
+static int
+ct_ccb_nexus_establish(ct)
+ struct ct_softc *ct;
+{
+ struct scsi_low_softc *slp = &ct->sc_sclow;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
+ struct lun_info *li = slp->sl_Lnexus;
+ struct targ_info *ti = slp->sl_Tnexus;
+ struct ct_targ_info *cti = (void *) ti;
+ struct slccb *cb = slp->sl_Qnexus;
- ct_cr_write_1(bst, bsh, wd3s_did, ti->ti_id);
- ct_cr_write_1(bst, bsh, wd3s_lun, li->li_lun);
- ct_cr_write_1(bst, bsh, wd3s_ctrl, ct->sc_creg | CR_DMA);
- ct_cr_write_1(bst, bsh, wd3s_cph, 0);
- ct_cr_write_1(bst, bsh, wd3s_synch, cti->cti_syncreg);
- cthw_set_count(bst, bsh, 0);
- ct_cr_write_1(bst, bsh, wd3s_lun, li->li_lun); /* XXX */
+ ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
+
+ if ((ct->sc_satgo & CT_SAT_GOING) != 0)
+ {
+ ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen);
+ ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
+ }
+ if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
+ ct_cr_write_1(chp, wd3s_did, ti->ti_id);
+ else
+ ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD);
+ ct_cr_write_1(chp, wd3s_lun, li->li_lun);
+ ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg);
return 0;
}
+static int
+ct_unbusy(ct)
+ struct ct_softc *ct;
+{
+ struct scsi_low_softc *slp = &ct->sc_sclow;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
+ int wc;
+ register u_int8_t regv;
+
+ for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++)
+ {
+ regv = ct_stat_read_1(chp);
+ if ((regv & (STR_BSY | STR_CIP)) == 0)
+ return 0;
+ if (regv == (u_int8_t) -1)
+ return EIO;
+
+ SCSI_LOW_DELAY(CT_DELAY_INTERVAL);
+ }
+
+ printf("%s: unbusy timeout\n", slp->sl_xname);
+ return EBUSY;
+}
+
+static int
+ct_catch_intr(ct)
+ struct ct_softc *ct;
+{
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
+ int wc;
+ register u_int8_t regv;
+
+ for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++)
+ {
+ regv = ct_stat_read_1(chp);
+ if ((regv & (STR_INT | STR_BSY | STR_CIP)) == STR_INT)
+ return 0;
+
+ SCSI_LOW_DELAY(CT_DELAY_INTERVAL);
+ }
+ return EJUSTRETURN;
+}
+
int
ctintr(arg)
void *arg;
{
struct ct_softc *ct = arg;
struct scsi_low_softc *slp = &ct->sc_sclow;
- bus_space_tag_t bst = ct->sc_iot;
- bus_space_handle_t bsh = ct->sc_ioh;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
struct targ_info *ti;
struct physio_proc *pp;
struct buf *bp;
- int len, satgo;
+ u_int derror, flags;
+ int len, satgo, error;
u_int8_t scsi_status, regv;
+again:
if (slp->sl_flags & HW_INACTIVE)
return 0;
/**************************************************
* Get status & bus phase
**************************************************/
- if ((ct_stat_read_1(bst, bsh) & STR_INT) == 0)
+ if ((ct_stat_read_1(chp) & STR_INT) == 0)
return 0;
- scsi_status = ct_cr_read_1(bst, bsh, wd3s_stat);
+ scsi_status = ct_cr_read_1(chp, wd3s_stat);
if (scsi_status == ((u_int8_t) -1))
return 1;
/**************************************************
* Check reselection, or nexus
**************************************************/
- if (scsi_status == BSR_RESEL)
+ if (scsi_status == BSR_RESEL || scsi_status == BSR_AFM_RESEL)
{
- if (ct_reselected(ct) == EJUSTRETURN)
+ if (ct_reselected(ct, scsi_status) == EJUSTRETURN)
return 1;
}
- if ((ti = slp->sl_nexus) == NULL)
+ if ((ti = slp->sl_Tnexus) == NULL)
return 1;
/**************************************************
@@ -735,8 +1001,10 @@ ctintr(arg)
scsi_low_print(slp, NULL);
printf("%s: scsi_status 0x%x\n\n", slp->sl_xname,
(u_int) scsi_status);
+#ifdef DDB
if (ct_debug > 1)
- Debugger();
+ SCSI_LOW_DEBUGGER("ct");
+#endif /* DDB */
}
#endif /* CT_DEBUG */
@@ -744,7 +1012,7 @@ ctintr(arg)
* Internal scsi phase
**************************************************/
satgo = ct->sc_satgo;
- ct->sc_satgo = 0;
+ ct->sc_satgo &= ~CT_SAT_GOING;
switch (ti->ti_phase)
{
@@ -756,15 +1024,14 @@ ctintr(arg)
ct_phase_error(ct, scsi_status);
return 1;
}
- scsi_low_arbit_win(slp, ti);
+ scsi_low_arbit_win(slp);
SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
return 1;
}
else
{
- scsi_low_arbit_win(slp, ti);
- SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
+ scsi_low_arbit_win(slp);
+ SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); /* XXX */
}
break;
@@ -787,11 +1054,15 @@ ctintr(arg)
(*ct->ct_dma_xfer_stop) (ct);
ct->sc_dma &= ~CT_DMA_DMASTART;
}
- else
+ else if (ct->sc_dma & CT_DMA_PIOSTART)
{
(*ct->ct_pio_xfer_stop) (ct);
ct->sc_dma &= ~CT_DMA_PIOSTART;
}
+ else
+ {
+ scsi_low_data_finish(slp);
+ }
}
break;
}
@@ -815,48 +1086,78 @@ ctintr(arg)
case BSR_DATAOUT:
SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
- return 1;
+ {
+ ct_attention(ct);
+ }
goto common_data_phase;
case BSR_DATAIN:
SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
- return 1;
-
-common_data_phase:
- if (slp->sl_scp.scp_datalen <= 0)
{
- ct_io_xfer(ct);
- return 1;
+ ct_attention(ct);
}
- slp->sl_flags |= HW_PDMASTART;
- if ((ct->sc_xmode & CT_XMODE_PIO) != 0 &&
- (slp->sl_scp.scp_datalen % DEV_BSIZE) == 0)
+common_data_phase:
+ if (slp->sl_scp.scp_datalen > 0)
{
- pp = physio_proc_enter(bp);
- ct->sc_dma |= CT_DMA_PIOSTART;
- (*ct->ct_pio_xfer_start) (ct);
- physio_proc_leave(pp);
- return 1;
+ slp->sl_flags |= HW_PDMASTART;
+ if ((ct->sc_xmode & CT_XMODE_PIO) != 0)
+ {
+ pp = physio_proc_enter(bp);
+ error = (*ct->ct_pio_xfer_start) (ct);
+ physio_proc_leave(pp);
+ if (error == 0)
+ {
+ ct->sc_dma |= CT_DMA_PIOSTART;
+ return 1;
+ }
+ }
+
+ if ((ct->sc_xmode & CT_XMODE_DMA) != 0)
+ {
+ error = (*ct->ct_dma_xfer_start) (ct);
+ if (error == 0)
+ {
+ ct->sc_dma |= CT_DMA_DMASTART;
+ return 1;
+ }
+ }
}
else
- {
- ct->sc_dma |= CT_DMA_DMASTART;
- (*ct->ct_dma_xfer_start) (ct);
- ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_TFR_INFO);
+ {
+ if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
+ {
+ if (!(slp->sl_flags & HW_READ_PADDING))
+ {
+ printf("%s: read padding required\n", slp->sl_xname);
+ return 1;
+ }
+ }
+ else
+ {
+ if (!(slp->sl_flags & HW_WRITE_PADDING))
+ {
+ printf("%s: write padding required\n", slp->sl_xname);
+ return 1;
+ }
+ }
+ slp->sl_flags |= HW_PDMASTART;
}
+
+ ct_io_xfer(ct);
return 1;
case BSR_CMDOUT:
SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
if (scsi_low_cmd(slp, ti) != 0)
- break;
+ {
+ ct_attention(ct);
+ }
- if (ct_xfer(ct,
- slp->sl_scp.scp_cmd,
+ if (ct_xfer(ct, slp->sl_scp.scp_cmd,
slp->sl_scp.scp_cmdlen,
- SCSI_LOW_WRITE) != 0)
+ SCSI_LOW_WRITE, &derror) != 0)
{
printf("%s: scsi cmd xfer short\n",
slp->sl_xname);
@@ -865,20 +1166,28 @@ common_data_phase:
case BSR_STATIN:
SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
-#ifdef CT_USE_CCSEQ
- if (scsi_low_is_msgout_continue(ti) != 0 ||
- ct->sc_atten != 0)
+ if ((ct_io_control & CT_USE_CCSEQ) != 0)
{
- ct_xfer(ct, &ti->ti_status, 1, SCSI_LOW_READ);
+ if (scsi_low_is_msgout_continue(ti, 0) != 0 ||
+ ct->sc_atten != 0)
+ {
+ ct_xfer(ct, &regv, 1, SCSI_LOW_READ,
+ &derror);
+ scsi_low_statusin(slp, ti,
+ regv | derror);
+ }
+ else
+ {
+ ct->sc_satgo |= CT_SAT_GOING;
+ cthw_set_count(chp, 0);
+ cthw_phase_bypass(ct, 0x41);
+ }
}
else
{
- cthw_set_count(bst, bsh, 0);
- cthw_phase_bypass(ct, 0x41);
+ ct_xfer(ct, &regv, 1, SCSI_LOW_READ, &derror);
+ scsi_low_statusin(slp, ti, regv | derror);
}
-#else /* !CT_USE_CCSEQ */
- ct_xfer(ct, &ti->ti_status, 1, SCSI_LOW_READ);
-#endif /* !CT_USE_CCSEQ */
return 1;
case BSR_UNSPINFO0:
@@ -890,20 +1199,44 @@ common_data_phase:
case BSR_MSGOUT:
SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
- len = scsi_low_msgout(slp, ti);
- if (ct_xfer(ct, ti->ti_msgoutstr, len, SCSI_LOW_WRITE))
+ flags = SCSI_LOW_MSGOUT_UNIFY;
+ if (ti->ti_ophase != ti->ti_phase)
+ flags |= SCSI_LOW_MSGOUT_INIT;
+ len = scsi_low_msgout(slp, ti, flags);
+
+ if (len > 1 && slp->sl_atten == 0)
+ {
+ ct_attention(ct);
+ }
+
+ if (ct_xfer(ct, ti->ti_msgoutstr, len,
+ SCSI_LOW_WRITE, &derror) != 0)
{
printf("%s: scsi msgout xfer short\n",
slp->sl_xname);
- scsi_low_assert_msg(slp, ti,
- SCSI_LOW_MSG_ABORT, 1);
}
+ SCSI_LOW_DEASSERT_ATN(slp);
+ ct->sc_atten = 0;
return 1;
case BSR_MSGIN:/* msg in */
SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
- ct_xfer(ct, &regv, 1, SCSI_LOW_READ);
- scsi_low_msgin(slp, ti, regv);
+
+ ct_xfer(ct, &regv, 1, SCSI_LOW_READ, &derror);
+ if (scsi_low_msgin(slp, ti, regv | derror) == 0)
+ {
+ if (scsi_low_is_msgout_continue(ti, 0) != 0)
+ {
+ /* XXX: scsi_low_attetion */
+ scsi_low_attention(slp);
+ }
+ }
+
+ if ((ct_io_control & CT_FAST_INTR) != 0)
+ {
+ if (ct_catch_intr(ct) == 0)
+ goto again;
+ }
return 1;
}
}
@@ -916,6 +1249,7 @@ common_data_phase:
{
case BSR_SATSDP: /* SAT with save data pointer */
SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
+ ct->sc_satgo |= CT_SAT_GOING;
scsi_low_msgin(slp, ti, MSG_SAVESP);
cthw_phase_bypass(ct, 0x41);
return 1;
@@ -924,17 +1258,30 @@ common_data_phase:
/*
* emulate statusin => msgin
*/
- ti->ti_status = ct_cr_read_1(bst, bsh, wd3s_lun);
+ SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
+ scsi_low_statusin(slp, ti, ct_cr_read_1(chp, wd3s_lun));
+
SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
- SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC);
+ scsi_low_msgin(slp, ti, MSG_COMP);
+
scsi_low_disconnected(slp, ti);
return 1;
case BSR_ACKREQ: /* negate ACK */
if (ct->sc_atten != 0)
- cthw_attention(ct);
+ {
+ ct_attention(ct);
+ }
- ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_NEGATE_ACK);
+ ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK);
+ if ((ct_io_control & CT_FAST_INTR) != 0)
+ {
+ /* XXX:
+ * Should clear a pending interrupt and
+ * sync with a next interrupt!
+ */
+ ct_catch_intr(ct);
+ }
return 1;
case BSR_DISC: /* disconnect */
@@ -945,7 +1292,7 @@ common_data_phase:
* emulate disconnect msg
*/
SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
- SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC);
+ scsi_low_msgin(slp, ti, MSG_DISCON);
}
scsi_low_disconnected(slp, ti);
return 1;
diff --git a/sys/dev/ct/ct_isa.c b/sys/dev/ct/ct_isa.c
index 5ca8006..ec38efe 100644
--- a/sys/dev/ct/ct_isa.c
+++ b/sys/dev/ct/ct_isa.c
@@ -75,6 +75,7 @@
#include <machine/resource.h>
#include <sys/bus.h>
#include <sys/rman.h>
+#include <machine/md_var.h>
#include <pc98/pc98/pc98.h>
#include <isa/isavar.h>
@@ -100,6 +101,9 @@ static int ct_space_map(device_t, struct bshw *,
static void ct_space_unmap(device_t, struct ct_softc *);
static struct bshw *ct_find_hw(device_t);
static void ct_dmamap(void *, bus_dma_segment_t *, int, int);
+static void ct_isa_bus_access_weight __P((struct ct_bus_access_handle *));
+static void ct_isa_dmasync_before __P((struct ct_softc *));
+static void ct_isa_dmasync_after __P((struct ct_softc *));
struct ct_isa_softc {
struct ct_softc sc_ct;
@@ -132,6 +136,7 @@ ct_isa_match(device_t dev)
{
struct bshw *hw;
struct resource *port_res, *mem_res;
+ struct ct_bus_access_handle ch;
int rv;
if (ISA_PNP_PROBE(device_get_parent(dev), dev, ct_pnp_ids) == ENXIO)
@@ -146,17 +151,20 @@ ct_isa_match(device_t dev)
if (ct_space_map(dev, hw, &port_res, &mem_res) != 0)
return ENXIO;
- rv = ctprobesubr(rman_get_bustag(port_res),
- rman_get_bushandle(port_res),
- 0, BSHW_DEFAULT_HOSTID, BSHW_DEFAULT_CHIPCLK);
+ bzero(&ch, sizeof(ch));
+ ch.ch_iot = rman_get_bustag(port_res);
+ ch.ch_ioh = rman_get_bushandle(port_res),
+ ch.ch_bus_weight = ct_isa_bus_access_weight;
+
+ rv = ctprobesubr(&ch, 0, BSHW_DEFAULT_HOSTID,
+ BSHW_DEFAULT_CHIPCLK, NULL);
if (rv != 0)
{
struct bshw_softc bshw_tab;
struct bshw_softc *bs = &bshw_tab;
memset(bs, 0, sizeof(*bs));
- bshw_read_settings(rman_get_bustag(port_res),
- rman_get_bushandle(port_res), bs);
+ bshw_read_settings(&ch, bs);
bus_set_resource(dev, SYS_RES_IRQ, 0, bs->sc_irq, 1);
bus_set_resource(dev, SYS_RES_DRQ, 0, bs->sc_drq, 1);
}
@@ -175,12 +183,14 @@ ct_isa_attach(device_t dev)
{
struct ct_isa_softc *pct = device_get_softc(dev);
struct ct_softc *ct = &pct->sc_ct;
+ struct ct_bus_access_handle *chp = &ct->sc_ch;
struct scsi_low_softc *slp = &ct->sc_sclow;
struct bshw_softc *bs = &pct->sc_bshw;
struct bshw *hw;
- int irq_rid, drq_rid;
+ int irq_rid, drq_rid, chiprev;
u_int8_t *vaddr;
bus_addr_t addr;
+ intrmask_t s;
hw = ct_find_hw(dev);
if (ct_space_map(dev, hw, &ct->port_res, &ct->mem_res) != 0) {
@@ -188,12 +198,14 @@ ct_isa_attach(device_t dev)
return ENXIO;
}
- ct->sc_iot = rman_get_bustag(ct->port_res);
- ct->sc_ioh = rman_get_bushandle(ct->port_res);
+ bzero(chp, sizeof(*chp));
+ chp->ch_iot = rman_get_bustag(ct->port_res);
+ chp->ch_ioh = rman_get_bushandle(ct->port_res);
if (ct->mem_res) {
- ct->sc_memt = rman_get_bustag(ct->mem_res);
- ct->sc_memh = rman_get_bushandle(ct->mem_res);
+ chp->ch_memt = rman_get_bustag(ct->mem_res);
+ chp->ch_memh = rman_get_bushandle(ct->mem_res);
}
+ chp->ch_bus_weight = ct_isa_bus_access_weight;
irq_rid = 0;
ct->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &irq_rid, 0, ~0,
@@ -206,6 +218,14 @@ ct_isa_attach(device_t dev)
return ENXIO;
}
+ if (ctprobesubr(chp, 0, BSHW_DEFAULT_HOSTID,
+ BSHW_DEFAULT_CHIPCLK, &chiprev) == 0)
+ {
+ device_printf(dev, "hardware missing\n");
+ ct_space_unmap(dev, ct);
+ return ENXIO;
+ }
+
/* setup DMA map */
if (bus_dma_tag_create(NULL, 1, 0,
BUS_SPACE_MAXADDR_24BIT, BUS_SPACE_MAXADDR,
@@ -229,11 +249,14 @@ ct_isa_attach(device_t dev)
/* setup machdep softc */
bs->sc_hw = hw;
+ bs->sc_io_control = 0;
bs->sc_bounce_phys = (u_int8_t *)addr;
bs->sc_bounce_addr = vaddr;
bs->sc_bounce_size = MAXBSIZE;
bs->sc_minphys = (1 << 24);
- bshw_read_settings(ct->sc_iot, ct->sc_ioh, bs);
+ bs->sc_dmasync_before = ct_isa_dmasync_before;
+ bs->sc_dmasync_after = ct_isa_dmasync_after;
+ bshw_read_settings(chp, bs);
/* setup ct driver softc */
ct->ct_hw = bs;
@@ -245,17 +268,54 @@ ct_isa_attach(device_t dev)
ct->ct_synch_setup = bshw_synch_setup;
ct->sc_xmode = CT_XMODE_DMA;
- if (ct->sc_memh != NULL)
+ if (chp->ch_memh != NULL)
ct->sc_xmode |= CT_XMODE_PIO;
- ct->sc_chiprev = CT_WD33C93_B;
- ct->sc_chipclk = BSHW_DEFAULT_CHIPCLK;
+
+ ct->sc_chiprev = chiprev;
+ switch (chiprev)
+ {
+ case CT_WD33C93:
+ /* s = "WD33C93"; */
+ ct->sc_chipclk = 8;
+ break;
+ case CT_WD33C93_A:
+ if (DVCFG_MAJOR(device_get_flags(dev)) > 0)
+ {
+ /* s = "AM33C93_A"; */
+ ct->sc_chipclk = 20;
+ ct->sc_chiprev = CT_AM33C93_A;
+ }
+ else
+ {
+ /* s = "WD33C93_A"; */
+ ct->sc_chipclk = 10;
+ }
+ break;
+
+ case CT_AM33C93_A:
+ /* s = "AM33C93_A"; */
+ ct->sc_chipclk = 20;
+ break;
+
+ default:
+ case CT_WD33C93_B:
+ /* s = "WD33C93_B"; */
+ ct->sc_chipclk = 20;
+ break;
+ }
+#if 0
+ printf("%s: chiprev %s chipclk %d Mhz\n",
+ slp->sl_dev.dv_xname, s, ct->sc_chipclk);
+#endif
slp->sl_dev = dev;
slp->sl_hostid = bs->sc_hostid;
slp->sl_irq = isa_get_irq(dev);
slp->sl_cfgflags = device_get_flags(dev);
+ s = splcam();
ctattachsubr(ct);
+ splx(s);
if (bus_setup_intr(dev, ct->irq_res, INTR_TYPE_CAM,
(driver_intr_t *)ctintr, ct, &ct->sc_ih)) {
@@ -320,3 +380,29 @@ ct_dmamap(void *arg, bus_dma_segment_t *seg, int nseg, int error)
*addr = seg->ds_addr;
}
+
+static void
+ct_isa_bus_access_weight(chp)
+ struct ct_bus_access_handle *chp;
+{
+
+ outb(0x5f, 0);
+}
+
+static void
+ct_isa_dmasync_before(ct)
+ struct ct_softc *ct;
+{
+
+ if (need_pre_dma_flush)
+ wbinvd();
+}
+
+static void
+ct_isa_dmasync_after(ct)
+ struct ct_softc *ct;
+{
+
+ if (need_post_dma_flush)
+ invd();
+}
diff --git a/sys/dev/ct/ct_machdep.h b/sys/dev/ct/ct_machdep.h
index 195af5b..be10331 100644
--- a/sys/dev/ct/ct_machdep.h
+++ b/sys/dev/ct/ct_machdep.h
@@ -1,12 +1,12 @@
/* $FreeBSD$ */
-/* $NecBSD: ct_machdep.h,v 1.4 1999/07/23 20:54:00 honda Exp $ */
+/* $NecBSD: ct_machdep.h,v 1.4.12.2 2001/06/20 06:13:34 honda Exp $ */
/* $NetBSD$ */
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1995, 1996, 1997, 1998
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
- * Copyright (c) 1995, 1996, 1997, 1998
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
* Naofumi HONDA. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,8 @@
#ifndef _CT_MACHDEP_H_
#define _CT_MACHDEP_H_
+#include "opt_ct.h"
+
/*
* Principal rules:
* 1) do not use bus_space_write/read_X directly in ct.c.
@@ -43,101 +45,167 @@
*/
/* special weight if requried */
-#define CT_BUS_WEIGHT
+#ifdef CT_BUS_WEIGHT
+#undef CT_BUS_WEIGHT
+#define CT_BUS_WEIGHT(chp) \
+{ \
+ if ((chp)->ch_bus_weight != NULL) \
+ (chp)->ch_bus_weight((chp)); \
+}
+#else /* !CT_BUS_WEIGHT */
+#define CT_BUS_WEIGHT(chp)
+#endif /* !CT_BUS_WEIGHT */
/* port offset */
+#ifndef CT_USE_RELOCATE_OFFSET
#define addr_port 0
#define stat_port 0
#define ctrl_port 2
#define cmd_port 4
+#else /* CT_USE_RELOCATE_OFFSET */
+#define addr_port ((chp)->ch_offset[0])
+#define stat_port ((chp)->ch_offset[1])
+#define ctrl_port ((chp)->ch_offset[2])
+#define cmd_port ((chp)->ch_offset[3])
+#endif /* CT_USE_RELOCATE_OFFSET */
/*
* All port accesses primitive methods
*/
-static __inline u_int8_t ct_cr_read_1 __P((bus_space_tag_t, bus_space_handle_t, bus_addr_t));
-static __inline void ct_cr_write_1 __P((bus_space_tag_t, bus_space_handle_t, bus_addr_t, u_int8_t));
-static __inline void ct_write_cmds __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *, int));
-static __inline u_int cthw_get_count __P((bus_space_tag_t, bus_space_handle_t));
-static __inline void cthw_set_count __P((bus_space_tag_t, bus_space_handle_t, u_int));
+static __inline u_int8_t ct_stat_read_1
+ __P((struct ct_bus_access_handle *));
+static __inline u_int8_t ct_cmdp_read_1
+ __P((struct ct_bus_access_handle *));
+static __inline void ct_cmdp_write_1
+ __P((struct ct_bus_access_handle *, u_int8_t));
+static __inline u_int8_t ct_cr_read_1
+ __P((struct ct_bus_access_handle *, bus_addr_t));
+static __inline void ct_cr_write_1
+ __P((struct ct_bus_access_handle *, bus_addr_t, u_int8_t));
+static __inline void ct_write_cmds
+ __P((struct ct_bus_access_handle *, u_int8_t *, int));
+static __inline u_int cthw_get_count
+ __P((struct ct_bus_access_handle *));
+static __inline void cthw_set_count
+ __P((struct ct_bus_access_handle *, u_int));
+
+static __inline u_int8_t
+ct_stat_read_1(chp)
+ struct ct_bus_access_handle *chp;
+{
+ u_int8_t regv;
-#define ct_stat_read_1(bst, bsh) bus_space_read_1((bst), (bsh), stat_port)
+ regv = bus_space_read_1(chp->ch_iot, chp->ch_ioh, stat_port);
+ CT_BUS_WEIGHT(chp)
+ return regv;
+}
static __inline void
-cthw_set_count(bst, bsh, count)
- bus_space_tag_t bst;
- bus_space_handle_t bsh;
+cthw_set_count(chp, count)
+ struct ct_bus_access_handle *chp;
u_int count;
{
+ bus_space_tag_t bst = chp->ch_iot;
+ bus_space_handle_t bsh = chp->ch_ioh;
bus_space_write_1(bst, bsh, addr_port, wd3s_cnt);
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
bus_space_write_1(bst, bsh, ctrl_port, count >> 16);
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
bus_space_write_1(bst, bsh, ctrl_port, count >> 8);
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
bus_space_write_1(bst, bsh, ctrl_port, count);
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
}
static __inline u_int
-cthw_get_count(bst, bsh)
- bus_space_tag_t bst;
- bus_space_handle_t bsh;
+cthw_get_count(chp)
+ struct ct_bus_access_handle *chp;
{
+ bus_space_tag_t bst = chp->ch_iot;
+ bus_space_handle_t bsh = chp->ch_ioh;
u_int count;
bus_space_write_1(bst, bsh, addr_port, wd3s_cnt);
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
count = (((u_int) bus_space_read_1(bst, bsh, ctrl_port)) << 16);
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
count += (((u_int) bus_space_read_1(bst, bsh, ctrl_port)) << 8);
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
count += ((u_int) bus_space_read_1(bst, bsh, ctrl_port));
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
return count;
}
static __inline void
-ct_write_cmds(bst, bsh, cmd, len)
- bus_space_tag_t bst;
- bus_space_handle_t bsh;
+ct_write_cmds(chp, cmd, len)
+ struct ct_bus_access_handle *chp;
u_int8_t *cmd;
int len;
{
+ bus_space_tag_t bst = chp->ch_iot;
+ bus_space_handle_t bsh = chp->ch_ioh;
int i;
bus_space_write_1(bst, bsh, addr_port, wd3s_cdb);
+ CT_BUS_WEIGHT(chp)
for (i = 0; i < len; i ++)
+ {
bus_space_write_1(bst, bsh, ctrl_port, cmd[i]);
+ CT_BUS_WEIGHT(chp)
+ }
}
static __inline u_int8_t
-ct_cr_read_1(bst, bsh, offs)
- bus_space_tag_t bst;
- bus_space_handle_t bsh;
+ct_cr_read_1(chp, offs)
+ struct ct_bus_access_handle *chp;
bus_addr_t offs;
{
+ bus_space_tag_t bst = chp->ch_iot;
+ bus_space_handle_t bsh = chp->ch_ioh;
u_int8_t regv;
bus_space_write_1(bst, bsh, addr_port, offs);
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
regv = bus_space_read_1(bst, bsh, ctrl_port);
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
return regv;
}
static __inline void
-ct_cr_write_1(bst, bsh, offs, val)
- bus_space_tag_t bst;
- bus_space_handle_t bsh;
+ct_cr_write_1(chp, offs, val)
+ struct ct_bus_access_handle *chp;
bus_addr_t offs;
u_int8_t val;
{
+ bus_space_tag_t bst = chp->ch_iot;
+ bus_space_handle_t bsh = chp->ch_ioh;
bus_space_write_1(bst, bsh, addr_port, offs);
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
bus_space_write_1(bst, bsh, ctrl_port, val);
- CT_BUS_WEIGHT
+ CT_BUS_WEIGHT(chp)
+}
+
+static __inline u_int8_t
+ct_cmdp_read_1(chp)
+ struct ct_bus_access_handle *chp;
+{
+ u_int8_t regv;
+
+ regv = bus_space_read_1(chp->ch_iot, chp->ch_ioh, cmd_port);
+ CT_BUS_WEIGHT(chp)
+ return regv;
+}
+
+static __inline void
+ct_cmdp_write_1(chp, val)
+ struct ct_bus_access_handle *chp;
+ u_int8_t val;
+{
+
+ bus_space_write_1(chp->ch_iot, chp->ch_ioh, cmd_port, val);
+ CT_BUS_WEIGHT(chp)
}
#if defined(i386)
@@ -145,11 +213,4 @@ ct_cr_write_1(bst, bsh, offs, val)
#else /* !i386 */
#define SOFT_INTR_REQUIRED(slp)
#endif /* !i386 */
-
-#ifdef __FreeBSD__
-typedef unsigned long vaddr_t;
-
-#define delay(t) DELAY(t)
-#endif
-
#endif /* !_CT_MACHDEP_H_ */
diff --git a/sys/dev/ct/ctvar.h b/sys/dev/ct/ctvar.h
index 5ad3db1..235990a 100644
--- a/sys/dev/ct/ctvar.h
+++ b/sys/dev/ct/ctvar.h
@@ -1,12 +1,12 @@
/* $FreeBSD$ */
-/* $NecBSD: ctvar.h,v 1.4 1999/04/15 01:36:13 kmatsuda Exp $ */
+/* $NecBSD: ctvar.h,v 1.4.14.3 2001/06/20 06:13:34 honda Exp $ */
/* $NetBSD$ */
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1995, 1996, 1997, 1998
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
- * Copyright (c) 1995, 1996, 1997, 1998
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
* Naofumi HONDA. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,31 +43,53 @@
/*****************************************************************
* Host adapter structure
*****************************************************************/
+struct ct_bus_access_handle {
+ bus_space_tag_t ch_iot; /* core chip ctrl port tag */
+ bus_space_tag_t ch_delayt; /* delay port tag */
+ bus_space_tag_t ch_datat; /* data port tag (pio) */
+ bus_space_tag_t ch_memt; /* data port tag (shm) */
+
+ bus_space_handle_t ch_ioh;
+ bus_space_handle_t ch_delaybah;
+ bus_space_handle_t ch_datah;
+ bus_space_handle_t ch_memh;
+
+ void (*ch_bus_weight) __P((struct ct_bus_access_handle *));
+
+#ifdef CT_USE_RELOCATE_OFFSET
+ bus_addr_t ch_offset[4];
+#endif /* CT_USE_RELOCATE_OFFSET */
+};
+
struct ct_softc {
struct scsi_low_softc sc_sclow; /* generic data */
+ struct ct_bus_access_handle sc_ch; /* bus access handle */
+
+#ifdef __NetBSD__
+ bus_dma_tag_t sc_dmat; /* data DMA tag */
+
+ void *sc_ih;
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
struct resource *port_res;
struct resource *mem_res;
struct resource *irq_res;
struct resource *drq_res;
- bus_space_tag_t sc_iot; /* core chip ctrl port tag */
- bus_space_tag_t sc_datat; /* data port tag (pio) */
- bus_space_tag_t sc_memt; /* data port tag (shm) */
bus_dma_tag_t sc_dmat; /* data DMA tag */
bus_dmamap_t sc_dmamapt; /* data DMAMAP tag */
- bus_space_handle_t sc_ioh;
- bus_space_handle_t sc_datah;
- bus_space_handle_t sc_memh;
-
void *sc_ih;
- int sc_wc; /* weight counter */
+#endif /* __FreeBSD__ */
int sc_chiprev; /* chip version */
-#define CT_WD33C93_A 0x00000
-#define CT_WD33C93_B 0x10000
-#define CT_WD33C93_C 0x20000
+#define CT_WD33C93 0x00000
+#define CT_WD33C93_A 0x10000
+#define CT_AM33C93_A 0x10001
+#define CT_WD33C93_B 0x20000
+#define CT_WD33C93_C 0x30000
int sc_xmode;
#define CT_XMODE_PIO 1
@@ -80,6 +102,7 @@ struct ct_softc {
int sc_satgo; /* combination cmd start */
#define CT_SAT_GOING 1
+ int sc_tmaxcnt;
int sc_atten; /* attention */
u_int8_t sc_creg; /* control register value */
@@ -89,20 +112,22 @@ struct ct_softc {
u_int cs_syncr;
} *sc_sdp; /* synchronous data table pt */
+ struct ct_synch_data sc_default_sdt[16];
+
/*
* Machdep stuff.
*/
void *ct_hw; /* point to bshw_softc etc ... */
- void (*ct_dma_xfer_start) __P((struct ct_softc *));
- void (*ct_pio_xfer_start) __P((struct ct_softc *));
+ int (*ct_dma_xfer_start) __P((struct ct_softc *));
+ int (*ct_pio_xfer_start) __P((struct ct_softc *));
void (*ct_dma_xfer_stop) __P((struct ct_softc *));
void (*ct_pio_xfer_stop) __P((struct ct_softc *));
void (*ct_bus_reset) __P((struct ct_softc *));
- void (*ct_synch_setup) __P((struct ct_softc *, struct lun_info *));
+ void (*ct_synch_setup) __P((struct ct_softc *, struct targ_info *));
};
/*****************************************************************
- * Target information
+ * Lun information
*****************************************************************/
struct ct_targ_info {
struct targ_info cti_ti;
@@ -113,14 +138,7 @@ struct ct_targ_info {
/*****************************************************************
* PROTO
*****************************************************************/
-#ifdef __NetBSD__
-#include <i386/Cbus/dev/ct/ct_machdep.h>
-#endif
-#ifdef __FreeBSD__
-#include <dev/ct/ct_machdep.h>
-#endif
-
-int ctprobesubr __P((bus_space_tag_t, bus_space_handle_t ioh, u_int, int, u_int));
+int ctprobesubr __P((struct ct_bus_access_handle *, u_int, int, u_int, int *));
void ctattachsubr __P((struct ct_softc *));
int ctprint __P((void *, const char *));
int ctintr __P((void *));
diff --git a/sys/dev/ncv/ncr53c500.c b/sys/dev/ncv/ncr53c500.c
index 73bc3df..9fa15f0 100644
--- a/sys/dev/ncv/ncr53c500.c
+++ b/sys/dev/ncv/ncr53c500.c
@@ -1,15 +1,16 @@
/* $FreeBSD$ */
-/* $NecBSD: ncr53c500.c,v 1.30 1999/07/23 21:00:04 honda Exp $ */
+/* $NecBSD: ncr53c500.c,v 1.30.12.3 2001/06/26 07:31:41 honda Exp $ */
/* $NetBSD$ */
#define NCV_DEBUG
#define NCV_STATICS
+#define NCV_IO_CONTROL_FLAGS (0)
/*
* [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.
*
* Redistribution and use in source and binary forms, with or without
@@ -40,19 +41,16 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/disklabel.h>
#if defined(__FreeBSD__) && __FreeBSD_version >= 500001
#include <sys/bio.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>
-#include <vm/vm.h>
-
#ifdef __NetBSD__
+#include <sys/device.h>
#include <machine/bus.h>
#include <machine/intr.h>
@@ -75,8 +73,6 @@
#ifdef __FreeBSD__
#include <machine/clock.h>
-#define delay(time) DELAY(time)
-
#include <machine/cpu.h>
#include <machine/bus_pio.h>
#include <machine/bus.h>
@@ -98,17 +94,26 @@ struct ncv_softc *ncvdata[NNCV];
#endif
#endif /* __FreeBSD__ */
+#define NCV_MAX_DATA_SIZE (64 * 1024)
+#define NCV_DELAY_MAX (2 * 1000 * 1000)
+#define NCV_DELAY_INTERVAL (1)
+#define NCV_PADDING_SIZE (32)
+
/***************************************************
- * DEBUG
+ * IO control
***************************************************/
-#ifndef DDB
-#define Debugger() panic("should call debugger here (ncr53c500.c)")
-#else /* ! DDB */
-#ifdef __FreeBSD__
-#define Debugger() Debugger("ncv")
-#endif /* __FreeBSD__ */
-#endif
+#define NCV_READ_INTERRUPTS_DRIVEN 0x0001
+#define NCV_WRITE_INTERRUPTS_DRIVEN 0x0002
+#define NCV_ENABLE_FAST_SCSI 0x0010
+#define NCV_FAST_INTERRUPTS 0x0100
+
+u_int ncv_io_control = NCV_IO_CONTROL_FLAGS;
+int ncv_data_read_bytes = 4096;
+int ncv_data_write_bytes = 4096;
+/***************************************************
+ * DEBUG
+ ***************************************************/
#ifdef NCV_DEBUG
int ncv_debug;
#endif /* NCV_DEBUG */
@@ -117,28 +122,23 @@ int ncv_debug;
struct ncv_statics {
int disconnect;
int reselect;
-} ncv_statics[NCV_NTARGETS];
+} ncv_statics;
#endif /* NCV_STATICS */
/***************************************************
- * ISA DEVICE STRUCTURE
+ * DEVICE STRUCTURE
***************************************************/
extern struct cfdriver ncv_cd;
/**************************************************************
* DECLARE
**************************************************************/
-#ifdef __NetBSD__
-extern int delaycount;
-#endif
-
/* static */
static void ncv_pio_read __P((struct ncv_softc *, u_int8_t *, u_int));
static void ncv_pio_write __P((struct ncv_softc *, u_int8_t *, u_int));
static int ncv_msg __P((struct ncv_softc *, struct targ_info *, u_int));
-static __inline int ncv_reselected __P((struct ncv_softc *));
-static __inline int ncv_disconnected __P((struct ncv_softc *, struct targ_info *));
-static __inline void ncv_pdma_end __P((struct ncv_softc *sc, struct targ_info *));
+static int ncv_reselected __P((struct ncv_softc *));
+static int ncv_disconnected __P((struct ncv_softc *, struct targ_info *));
static __inline void ncvhw_set_count __P((bus_space_tag_t, bus_space_handle_t, int));
static __inline u_int ncvhw_get_count __P((bus_space_tag_t, bus_space_handle_t));
@@ -146,6 +146,7 @@ static __inline void ncvhw_select_register_0 __P((bus_space_tag_t, bus_space_han
static __inline void ncvhw_select_register_1 __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *));
static __inline void ncvhw_fpush __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *, int));
+static void ncv_pdma_end __P((struct ncv_softc *sc, struct targ_info *));
static int ncv_world_start __P((struct ncv_softc *, int));
static void ncvhw_bus_reset __P((struct ncv_softc *));
static void ncvhw_reset __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *));
@@ -153,23 +154,30 @@ static int ncvhw_check __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *
static void ncvhw_init __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *));
static int ncvhw_start_selection __P((struct ncv_softc *sc, struct slccb *));
static void ncvhw_attention __P((struct ncv_softc *));
-static int ncv_nexus __P((struct ncv_softc *, struct targ_info *));
+static int ncv_ccb_nexus_establish __P((struct ncv_softc *));
+static int ncv_lun_nexus_establish __P((struct ncv_softc *));
+static int ncv_target_nexus_establish __P((struct ncv_softc *));
+static int ncv_targ_init __P((struct ncv_softc *, struct targ_info *, int));
+static int ncv_catch_intr __P((struct ncv_softc *));
#ifdef NCV_POWER_CONTROL
static int ncvhw_power __P((struct ncv_softc *, u_int));
-#endif
-static int ncv_targ_init __P((struct ncv_softc *, struct targ_info *));
+#endif /* NCV_POWER_CONTROL */
+static __inline void ncv_setup_and_start_pio __P((struct ncv_softc *, u_int));
struct scsi_low_funcs ncv_funcs = {
SC_LOW_INIT_T ncv_world_start,
SC_LOW_BUSRST_T ncvhw_bus_reset,
SC_LOW_TARG_INIT_T ncv_targ_init,
+ SC_LOW_LUN_INIT_T NULL,
SC_LOW_SELECT_T ncvhw_start_selection,
- SC_LOW_NEXUS_T ncv_nexus,
+ SC_LOW_NEXUS_T ncv_lun_nexus_establish,
+ SC_LOW_NEXUS_T ncv_ccb_nexus_establish,
SC_LOW_ATTEN_T ncvhw_attention,
SC_LOW_MSG_T ncv_msg,
+ SC_LOW_TIMEOUT_T NULL,
SC_LOW_POLL_T ncvintr,
NULL, /* SC_LOW_POWER_T ncvhw_power, */
@@ -185,7 +193,7 @@ ncvhw_select_register_0(iot, ioh, hw)
struct ncv_hw *hw;
{
- bus_space_write_1(iot, ioh, cr0_cfg4, hw->cfg4);
+ bus_space_write_1(iot, ioh, cr0_cfg4, hw->hw_cfg4);
}
static __inline void
@@ -195,7 +203,7 @@ ncvhw_select_register_1(iot, ioh, hw)
struct ncv_hw *hw;
{
- bus_space_write_1(iot, ioh, cr1_cfg5, hw->cfg5);
+ bus_space_write_1(iot, ioh, cr1_cfg5, hw->hw_cfg5);
}
static __inline void
@@ -211,6 +219,31 @@ ncvhw_fpush(iot, ioh, buf, len)
bus_space_write_1(iot, ioh, cr0_sfifo, buf[ptr]);
}
+static __inline void
+ncvhw_set_count(iot, ioh, count)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int count;
+{
+
+ bus_space_write_1(iot, ioh, cr0_tclsb, (u_int8_t) count);
+ bus_space_write_1(iot, ioh, cr0_tcmsb, (u_int8_t) (count >> NBBY));
+ bus_space_write_1(iot, ioh, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2)));
+}
+
+static __inline u_int
+ncvhw_get_count(iot, ioh)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+{
+ u_int count;
+
+ count = (u_int) bus_space_read_1(iot, ioh, cr0_tclsb);
+ count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tcmsb)) << NBBY;
+ count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tchsb)) << (NBBY * 2);
+ return count;
+}
+
static int
ncvhw_check(iot, ioh, hw)
bus_space_tag_t iot;
@@ -247,12 +280,12 @@ ncvhw_check(iot, ioh, hw)
bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI);
bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
- delay(100 * 1000);
+ SCSI_LOW_DELAY(100 * 1000);
/* check response */
bus_space_read_1(iot, ioh, cr0_stat);
stat = bus_space_read_1(iot, ioh, cr0_istat);
- delay(1000);
+ SCSI_LOW_DELAY(1000);
if (((stat & INTR_SBR) == 0) ||
(bus_space_read_1(iot, ioh, cr0_istat) & INTR_SBR))
@@ -295,14 +328,14 @@ ncvhw_init(iot, ioh, hw)
{
ncvhw_select_register_0(iot, ioh, hw);
- bus_space_write_1(iot, ioh, cr0_clk, hw->clk);
+ bus_space_write_1(iot, ioh, cr0_clk, hw->hw_clk);
bus_space_write_1(iot, ioh, cr0_srtout, SEL_TOUT);
bus_space_write_1(iot, ioh, cr0_period, 0);
bus_space_write_1(iot, ioh, cr0_offs, 0);
- bus_space_write_1(iot, ioh, cr0_cfg1, hw->cfg1);
- bus_space_write_1(iot, ioh, cr0_cfg2, hw->cfg2);
- bus_space_write_1(iot, ioh, cr0_cfg3, hw->cfg3);
+ bus_space_write_1(iot, ioh, cr0_cfg1, hw->hw_cfg1);
+ bus_space_write_1(iot, ioh, cr0_cfg2, hw->hw_cfg2);
+ bus_space_write_1(iot, ioh, cr0_cfg3, hw->hw_cfg3);
bus_space_write_1(iot, ioh, cr0_tchsb, 0);
ncvhw_select_register_1(iot, ioh, hw);
@@ -360,7 +393,7 @@ ncvhw_attention(sc)
{
bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, CMD_SETATN);
- delay(10);
+ SCSI_LOW_DELAY(10);
}
static void
@@ -385,17 +418,44 @@ ncvhw_start_selection(sc, cb)
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct targ_info *ti = cb->ti;
- int s;
- u_int8_t msg;
+ int s, len;
+ u_int flags;
+ u_int8_t cmd;
- msg = ID_MSG_SETUP(ti);
+ sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
sc->sc_compseq = 0;
+ if (scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0)
+ {
+ cmd = CMD_SELATN;
+ sc->sc_selstop = 0;
+ flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT;
+ }
+ else if (scsi_low_is_msgout_continue(ti,
+ SCSI_LOW_MSG_IDENTIFY | SCSI_LOW_MSG_SIMPLE_QTAG) == 0)
+ {
+ cmd = CMD_SELATN3;
+ sc->sc_selstop = 0;
+ flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT;
+ }
+ else
+ {
+ cmd = CMD_SELATNS;
+ sc->sc_selstop = 1;
+ flags = SCSI_LOW_MSGOUT_INIT;
+ }
+
ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
+ if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0)
+ return SCSI_LOW_START_FAIL;
- s = splhigh();
+ ncv_target_nexus_establish(sc);
+
+ len = scsi_low_msgout(slp, ti, flags);
+ if (sc->sc_selstop == 0)
+ scsi_low_cmd(slp, ti);
- if (slp->sl_disc > 0 &&
- (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat) & STAT_INT))
+ s = splhigh();
+ if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0)
{
splx(s);
return SCSI_LOW_START_FAIL;
@@ -403,27 +463,15 @@ ncvhw_start_selection(sc, cb)
bus_space_write_1(iot, ioh, cr0_dstid, ti->ti_id);
bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
- bus_space_write_1(iot, ioh, cr0_sfifo, msg);
-
- if (scsi_low_is_msgout_continue(ti) != 0)
+ ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len);
+ if (sc->sc_selstop == 0)
{
- bus_space_write_1(iot, ioh, cr0_cmd, CMD_SELATNS);
- sc->sc_selstop = 1;
- }
- else
- {
- /* XXX:
- * emulate nexus call because ncv bypasses CMD phase.
- */
- scsi_low_cmd(slp, ti);
ncvhw_fpush(iot, ioh,
slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
- bus_space_write_1(iot, ioh, cr0_cmd, CMD_SELATN);
- sc->sc_selstop = 0;
}
+ bus_space_write_1(iot, ioh, cr0_cmd, cmd);
splx(s);
- SCSI_LOW_TARGET_ASSERT_ATN(ti);
SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
return SCSI_LOW_START_OK;
}
@@ -437,25 +485,21 @@ ncv_world_start(sc, fdone)
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
u_int8_t stat;
-#ifdef __FreeBSD__
- intrmask_t s;
-#endif
+
+ if ((slp->sl_cfgflags & CFG_NOPARITY) == 0)
+ sc->sc_hw.hw_cfg1 |= C1_PARENB;
+ else
+ sc->sc_hw.hw_cfg1 &= ~C1_PARENB;
ncvhw_reset(iot, ioh, &sc->sc_hw);
ncvhw_init(iot, ioh, &sc->sc_hw);
-#ifdef __FreeBSD__
- s = splcam();
-#endif
scsi_low_bus_reset(slp);
ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat);
stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat);
-#ifdef __FreeBSD__
- splx(s);
-#endif
- delay(1000);
+ SCSI_LOW_DELAY(1000);
if (((stat & INTR_SBR) == 0) ||
(bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat) & INTR_SBR))
@@ -471,39 +515,61 @@ ncv_msg(sc, ti, msg)
struct targ_info *ti;
u_int msg;
{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
struct ncv_targ_info *nti = (void *) ti;
u_int hwcycle, period;
+ if ((msg & SCSI_LOW_MSG_WIDE) != 0)
+ {
+ if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
+ {
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
+ return EINVAL;
+ }
+ return 0;
+ }
+
if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
return 0;
period = ti->ti_maxsynch.period;
- hwcycle = 1000 / ((sc->sc_hw.clk == 0) ? 40 : (5 * sc->sc_hw.clk));
+ hwcycle = (sc->sc_hw.hw_clk == 0) ? 40 : (5 * sc->sc_hw.hw_clk);
+ hwcycle = 1000 / hwcycle;
if (period < 200 / 4 && period >= 100 / 4)
- nti->nti_reg_cfg3 |= C3_FSCSI;
+ nti->nti_reg_cfg3 |= sc->sc_hw.hw_cfg3_fscsi;
else
- nti->nti_reg_cfg3 &= ~C3_FSCSI;
+ nti->nti_reg_cfg3 &= ~sc->sc_hw.hw_cfg3_fscsi;
period = ((period * 40 / hwcycle) + 5) / 10;
nti->nti_reg_period = period & 0x1f;
nti->nti_reg_offset = ti->ti_maxsynch.offset;
+
+ bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period);
+ bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset);
+ bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3);
return 0;
}
static int
-ncv_targ_init(sc, ti)
+ncv_targ_init(sc, ti, action)
struct ncv_softc *sc;
struct targ_info *ti;
+ int action;
{
struct ncv_targ_info *nti = (void *) ti;
- ti->ti_maxsynch.period = sc->sc_hw.mperiod;
- ti->ti_maxsynch.offset = sc->sc_hw.moffset;
+ if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
+ {
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
+ ti->ti_maxsynch.period = sc->sc_hw.hw_mperiod;
+ ti->ti_maxsynch.offset = sc->sc_hw.hw_moffset;
- nti->nti_reg_cfg3 = sc->sc_hw.cfg3;
- nti->nti_reg_period = 0;
- nti->nti_reg_offset = 0;
+ nti->nti_reg_cfg3 = sc->sc_hw.hw_cfg3;
+ nti->nti_reg_period = 0;
+ nti->nti_reg_offset = 0;
+ }
return 0;
}
@@ -513,10 +579,10 @@ ncv_targ_init(sc, ti)
static int ncv_setup_img __P((struct ncv_hw *, u_int, int));
static int
-ncv_setup_img(hw, dvcfg, hsid)
+ncv_setup_img(hw, dvcfg, hostid)
struct ncv_hw *hw;
u_int dvcfg;
- int hsid;
+ int hostid;
{
if (NCV_CLKFACTOR(dvcfg) > CLK_35M_F)
@@ -527,35 +593,31 @@ ncv_setup_img(hw, dvcfg, hsid)
if (NCV_C5IMG(dvcfg) != 0)
{
- hw->cfg5 = NCV_C5IMG(dvcfg);
- hw->clk = NCV_CLKFACTOR(dvcfg);
+ hw->hw_cfg5 = NCV_C5IMG(dvcfg);
+ hw->hw_clk = NCV_CLKFACTOR(dvcfg);
- if (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M)
- hw->mperiod = 100 / 4;
+ if ((ncv_io_control & NCV_ENABLE_FAST_SCSI) != 0 &&
+ (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M) != 0)
+ hw->hw_mperiod = 100 / 4;
- /* XXX:
- * RATOC scsi cards have fatal fifo asic bug.
- * To avoid it, currently make sync offset 0 (async)!
- */
if (NCV_SPECIAL(dvcfg) & NCVHWCFG_FIFOBUG)
- {
- hw->mperiod = 0;
- hw->moffset = 0;
- }
+ hw->hw_cfg3_fclk = 0x04;
if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SCSI1)
- hw->cfg2 &= ~C2_SCSI2;
+ hw->hw_cfg2 &= ~C2_SCSI2;
if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SLOW)
- hw->cfg1 |= C1_SLOW;
+ hw->hw_cfg1 |= C1_SLOW;
}
/* setup configuration image 3 */
- if (hw->clk != CLK_40M_F && hw->clk <= CLK_25M_F)
- hw->cfg3 &= ~C3_FCLK;
+ if (hw->hw_clk != CLK_40M_F && hw->hw_clk <= CLK_25M_F)
+ hw->hw_cfg3 &= ~hw->hw_cfg3_fclk;
+ else
+ hw->hw_cfg3 |= hw->hw_cfg3_fclk;
/* setup configuration image 1 */
- hw->cfg1 = (hw->cfg1 & 0xf0) | hsid;
+ hw->hw_cfg1 = (hw->hw_cfg1 & 0xf0) | hostid;
return 0;
}
@@ -597,45 +659,34 @@ ncvattachsubr(sc)
printf("\n");
sc->sc_hw = ncv_template;
ncv_setup_img(&sc->sc_hw, slp->sl_cfgflags, slp->sl_hostid);
-#ifdef __FreeBSD__
- sc->sc_wc = 0x2000 * 2000; /* XXX need calibration */
-#else /* NetBSD */
- sc->sc_wc = delaycount * 2000; /* 2 sec */
-#endif
slp->sl_funcs = &ncv_funcs;
- (void) scsi_low_attach(slp, 2, NCV_NTARGETS, NCV_NLUNS,
- sizeof(struct ncv_targ_info));
+ slp->sl_flags |= HW_READ_PADDING;
+ sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
+
+ (void) scsi_low_attach(slp, 0, NCV_NTARGETS, NCV_NLUNS,
+ sizeof(struct ncv_targ_info), 0);
}
/**************************************************************
* PDMA
**************************************************************/
static __inline void
-ncvhw_set_count(iot, ioh, count)
- bus_space_tag_t iot;
- bus_space_handle_t ioh;
- int count;
+ncv_setup_and_start_pio(sc, reqlen)
+ struct ncv_softc *sc;
+ u_int reqlen;
{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
- bus_space_write_1(iot, ioh, cr0_tclsb, (u_int8_t) count);
- bus_space_write_1(iot, ioh, cr0_tcmsb, (u_int8_t) (count >> NBBY));
- bus_space_write_1(iot, ioh, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2)));
-}
-
-static __inline u_int
-ncvhw_get_count(iot, ioh)
- bus_space_tag_t iot;
- bus_space_handle_t ioh;
-{
- u_int count;
+ ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
+ ncvhw_set_count(iot, ioh, reqlen);
+ bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA);
- count = (u_int) bus_space_read_1(iot, ioh, cr0_tclsb);
- count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tcmsb)) << NBBY;
- count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tchsb)) << (NBBY * 2);
- return count;
+ ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
+ bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN);
}
-static __inline void
+static void
ncv_pdma_end(sc, ti)
struct ncv_softc *sc;
struct targ_info *ti;
@@ -646,6 +697,12 @@ ncv_pdma_end(sc, ti)
int len;
slp->sl_flags &= ~HW_PDMASTART;
+ if (slp->sl_Qnexus == NULL)
+ {
+ slp->sl_error |= PDMAERR;
+ goto out;
+ }
+
if (ti->ti_phase == PH_DATA)
{
len = ncvhw_get_count(sc->sc_iot, sc->sc_ioh);
@@ -653,29 +710,39 @@ ncv_pdma_end(sc, ti)
len += (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
cr0_sffl) & CR0_SFFLR_BMASK);
- if ((u_int) len <= (u_int) slp->sl_scp.scp_datalen)
+ if ((u_int) len <= (u_int) sc->sc_sdatalen)
{
- slp->sl_scp.scp_data += (slp->sl_scp.scp_datalen - len);
- slp->sl_scp.scp_datalen = len;
if ((slp->sl_scp.scp_direction == SCSI_LOW_READ) &&
sc->sc_tdatalen != len)
goto bad;
+
+ len = sc->sc_sdatalen - len;
+ if ((u_int) len > (u_int) slp->sl_scp.scp_datalen)
+ goto bad;
+
+ slp->sl_scp.scp_data += len;
+ slp->sl_scp.scp_datalen -= len;
}
else
{
bad:
+ if ((slp->sl_error & PDMAERR) == 0)
+ {
+ printf("%s: stragne cnt hw 0x%x soft 0x%x\n",
+ slp->sl_xname, len,
+ slp->sl_scp.scp_datalen);
+ }
slp->sl_error |= PDMAERR;
- printf("%s stragne count hw 0x%x soft 0x%x tlen 0x%x\n",
- slp->sl_xname, len, slp->sl_scp.scp_datalen,
- sc->sc_tdatalen);
}
+ scsi_low_data_finish(slp);
}
else
{
- printf("%s data phase miss\n", slp->sl_xname);
+ printf("%s: data phase miss\n", slp->sl_xname);
slp->sl_error |= PDMAERR;
}
+out:
ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
bus_space_write_1(iot, ioh, cr1_fstat, 0);
ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
@@ -690,23 +757,19 @@ ncv_pio_read(sc, buf, reqlen)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- int tout = sc->sc_wc;
+ int tout;
register u_int8_t fstat;
- ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
- bus_space_write_1(iot, ioh, cr1_pflag, 0);
-
- ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
- ncvhw_set_count(iot, ioh, reqlen);
- bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA);
-
- ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
- bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN);
+ ncv_setup_and_start_pio(sc, reqlen);
slp->sl_flags |= HW_PDMASTART;
+ sc->sc_sdatalen = reqlen;
+ tout = sc->sc_tmaxcnt;
- while (reqlen >= FIFO_F_SZ && tout > 0)
+ while (reqlen >= FIFO_F_SZ && tout -- > 0)
{
fstat = bus_space_read_1(iot, ioh, cr1_fstat);
+ if (fstat == (u_int8_t) -1)
+ goto out;
if (fstat & FIFO_F)
{
#define NCV_FAST32_ACCESS
@@ -719,51 +782,36 @@ ncv_pio_read(sc, buf, reqlen)
#endif /* !NCV_FAST32_ACCESS */
buf += FIFO_F_SZ;
reqlen -= FIFO_F_SZ;
- continue;
}
- else if (fstat & FIFO_BRK)
- break;
-
- tout --;
- }
-
- if (reqlen >= FIFO_2_SZ)
- {
- fstat = bus_space_read_1(iot, ioh, cr1_fstat);
- if (fstat & FIFO_2)
+ else
{
-#ifdef NCV_FAST32_ACCESS
- bus_space_read_multi_4(iot, ioh, cr1_fdata,
- (u_int32_t *) buf, FIFO_2_SZ / 4);
-#else /* !NCV_FAST32_ACCESS */
- bus_space_read_multi_2(iot, ioh, cr1_fdata,
- (u_int16_t *) buf, FIFO_2_SZ / 2);
-#endif /* !NCV_FAST32_ACCESS */
- buf += FIFO_2_SZ;
- reqlen -= FIFO_2_SZ;
+ if (fstat & FIFO_BRK)
+ break;
+
+ SCSI_LOW_DELAY(1);
}
}
- while (reqlen > 0 && tout > 0)
+ while (reqlen > 0 && tout -- > 0)
{
fstat = bus_space_read_1(iot, ioh, cr1_fstat);
if ((fstat & FIFO_E) == 0)
{
*buf++ = bus_space_read_1(iot, ioh, cr1_fdata);
reqlen --;
- continue;
}
- else if (fstat & FIFO_BRK)
- break;
+ else
+ {
+ if (fstat & FIFO_BRK)
+ break;
- tout --;
+ SCSI_LOW_DELAY(1);
+ }
}
+out:
ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
sc->sc_tdatalen = reqlen;
-
- if (tout <= 0)
- printf("%s pio read timeout\n", slp->sl_xname);
}
static void
@@ -775,27 +823,21 @@ ncv_pio_write(sc, buf, reqlen)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- int tout = sc->sc_wc;
+ int tout;
register u_int8_t fstat;
- ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
- bus_space_write_1(iot, ioh, cr1_pflag, 0);
-
- ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
- ncvhw_set_count(iot, ioh, reqlen);
- bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA);
-
- ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
- bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN);
+ ncv_setup_and_start_pio(sc, reqlen);
+ sc->sc_sdatalen = reqlen;
+ tout = sc->sc_tmaxcnt;
slp->sl_flags |= HW_PDMASTART;
- while (reqlen >= FIFO_F_SZ && tout > 0)
+ while (reqlen >= FIFO_F_SZ && tout -- > 0)
{
fstat = bus_space_read_1(iot, ioh, cr1_fstat);
if (fstat & FIFO_BRK)
goto done;
- if (fstat & FIFO_E)
+ if ((fstat & FIFO_E) != 0)
{
#ifdef NCV_FAST32_ACCESS
bus_space_write_multi_4(iot, ioh, cr1_fdata,
@@ -808,10 +850,12 @@ ncv_pio_write(sc, buf, reqlen)
reqlen -= FIFO_F_SZ;
}
else
- tout --;
+ {
+ SCSI_LOW_DELAY(1);
+ }
}
- while (reqlen > 0 && tout > 0)
+ while (reqlen > 0 && tout -- > 0)
{
fstat = bus_space_read_1(iot, ioh, cr1_fstat);
if (fstat & FIFO_BRK)
@@ -823,20 +867,19 @@ ncv_pio_write(sc, buf, reqlen)
reqlen --;
}
else
- tout --;
+ {
+ SCSI_LOW_DELAY(1);
+ }
}
done:
ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
-
- if (tout <= 0)
- printf("%s pio write timeout\n", slp->sl_xname);
}
/**************************************************************
* disconnect & reselect (HW low)
**************************************************************/
-static __inline int
+static int
ncv_reselected(sc)
struct ncv_softc *sc;
{
@@ -854,19 +897,20 @@ ncv_reselected(sc)
}
sid = (u_int) bus_space_read_1(iot, ioh, cr0_sfifo);
+ sid &= ~(1 << slp->sl_hostid);
sid = ffs(sid) - 1;
ti = scsi_low_reselected((struct scsi_low_softc *) sc, sid);
if (ti == NULL)
return EJUSTRETURN;
#ifdef NCV_STATICS
- ncv_statics[sid].reselect ++;
+ ncv_statics.reselect ++;
#endif /* NCV_STATICS */
bus_space_write_1(iot, ioh, cr0_dstid, sid);
return 0;
}
-static __inline int
+static int
ncv_disconnected(sc, ti)
struct ncv_softc *sc;
struct targ_info *ti;
@@ -876,12 +920,10 @@ ncv_disconnected(sc, ti)
bus_space_handle_t ioh = sc->sc_ioh;
bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
- bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1);
bus_space_write_1(iot, ioh, cr0_cmd, CMD_ENSEL);
#ifdef NCV_STATICS
- if (slp->sl_msgphase == MSGPH_DISC)
- ncv_statics[ti->ti_id].disconnect ++;
+ ncv_statics.disconnect ++;
#endif /* NCV_STATICS */
scsi_low_disconnected(slp, ti);
@@ -892,25 +934,60 @@ ncv_disconnected(sc, ti)
* SEQUENCER
**************************************************************/
static int
-ncv_nexus(sc, ti)
+ncv_target_nexus_establish(sc)
struct ncv_softc *sc;
- struct targ_info *ti;
{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ struct targ_info *ti = slp->sl_Tnexus;
+ struct ncv_targ_info *nti = (void *) ti;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct lun_info *li = ti->ti_li;
- struct ncv_targ_info *nti = (void *) ti;
- if (li->li_flags & SCSI_LOW_NOPARITY)
- bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1);
- else
- bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1 | C1_PARENB);
bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period);
bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset);
bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3);
return 0;
}
+static int
+ncv_lun_nexus_establish(sc)
+ struct ncv_softc *sc;
+{
+
+ return 0;
+}
+
+static int
+ncv_ccb_nexus_establish(sc)
+ struct ncv_softc *sc;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ struct slccb *cb = slp->sl_Qnexus;
+
+ sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
+ return 0;
+}
+
+static int
+ncv_catch_intr(sc)
+ struct ncv_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int wc;
+ register u_int8_t status;
+
+ for (wc = 0; wc < NCV_DELAY_MAX / NCV_DELAY_INTERVAL; wc ++)
+ {
+ status = bus_space_read_1(iot, ioh, cr0_stat);
+ if ((status & STAT_INT) != 0)
+ return 0;
+
+ SCSI_LOW_DELAY(NCV_DELAY_INTERVAL);
+ }
+ return EJUSTRETURN;
+}
+
int
ncvintr(arg)
void *arg;
@@ -922,9 +999,11 @@ ncvintr(arg)
struct targ_info *ti;
struct physio_proc *pp;
struct buf *bp;
- int len, identify;
+ u_int derror, flags;
+ int len;
u_int8_t regv, status, ireason;
+again:
if (slp->sl_flags & HW_INACTIVE)
return 0;
@@ -933,11 +1012,11 @@ ncvintr(arg)
********************************************/
ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
status = bus_space_read_1(iot, ioh, cr0_stat);
- if ((status & STAT_INT) == 0)
+ if ((status & STAT_INT) == 0 || status == (u_int8_t) -1)
return 0;
ireason = bus_space_read_1(iot, ioh, cr0_istat);
- if (ireason & INTR_SBR)
+ if ((ireason & INTR_SBR) != 0)
{
u_int8_t val;
@@ -960,8 +1039,10 @@ ncvintr(arg)
scsi_low_print(slp, NULL);
printf("%s st %x ist %x\n\n", slp->sl_xname,
status, ireason);
+#ifdef DDB
if (ncv_debug > 1)
- Debugger();
+ SCSI_LOW_DEBUGGER("ncv");
+#endif /* DDB */
}
#endif /* NCV_DEBUG */
@@ -976,16 +1057,18 @@ ncvintr(arg)
}
/* (II) nexus */
- if ((ti = slp->sl_nexus) == NULL)
+ if ((ti = slp->sl_Tnexus) == NULL)
return 0;
+ derror = 0;
if ((status & (STAT_PE | STAT_GE)) != 0)
{
slp->sl_error |= PARITYERR;
- if (ti->ti_phase == PH_MSGIN)
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 1);
+ if ((status & PHASE_MASK) == MESSAGE_IN_PHASE)
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
else
scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1);
+ derror = SCSI_LOW_DATA_PE;
}
if ((ireason & (INTR_DIS | INTR_ILL)) != 0)
@@ -1004,9 +1087,8 @@ ncvintr(arg)
switch (ti->ti_phase)
{
case PH_SELSTART:
- scsi_low_arbit_win(slp, ti);
+ scsi_low_arbit_win(slp);
SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
- identify = 0;
if (sc->sc_selstop == 0)
{
@@ -1015,49 +1097,41 @@ ncvintr(arg)
* DATA PHASE:
* MSGIN : target wants to disconnect the host.
* STATUSIN : immediate command completed.
+ * CMD PHASE : command out failed
* MSGOUT : identify command failed.
*/
if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
break;
- identify = 1;
}
else
{
- /* XXX:
- * Here scsi phase should be MSGOUT.
- * The driver NEVER supports devices
- * which neglect ATN singal.
- */
if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
+ break;
+ if ((ireason & INTR_FC) != 0)
{
- slp->sl_error |= FATALIO;
- scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
- "msgout error");
- return 1;
+ SCSI_LOW_ASSERT_ATN(slp);
}
-
- if ((ireason & INTR_FC) == 0)
- identify = 1;
- }
-
- if (identify != 0)
- {
- printf("%s msg identify failed\n", slp->sl_xname);
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
}
+ SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
break;
case PH_RESEL:
+ ncv_target_nexus_establish(sc);
if ((status & PHASE_MASK) != MESSAGE_IN_PHASE)
{
+ printf("%s: unexpected phase after reselect\n",
+ slp->sl_xname);
+ slp->sl_error |= FATALIO;
scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
return 1;
}
break;
default:
- if (slp->sl_flags & HW_PDMASTART)
+ if ((slp->sl_flags & HW_PDMASTART) != 0)
+ {
ncv_pdma_end(sc, ti);
+ }
break;
}
@@ -1069,27 +1143,95 @@ ncvintr(arg)
case DATA_OUT_PHASE: /* data out */
SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
pp = physio_proc_enter(bp);
- ncv_pio_write(sc, slp->sl_scp.scp_data, slp->sl_scp.scp_datalen);
+ if (slp->sl_scp.scp_datalen <= 0)
+ {
+ if ((ireason & INTR_BS) == 0)
+ break;
+
+ if ((slp->sl_error & PDMAERR) == 0)
+ printf("%s: data underrun\n", slp->sl_xname);
+ slp->sl_error |= PDMAERR;
+
+ if ((slp->sl_flags & HW_WRITE_PADDING) != 0)
+ {
+ u_int8_t padding[NCV_PADDING_SIZE];
+
+ SCSI_LOW_BZERO(padding, sizeof(padding));
+ ncv_pio_write(sc, padding, sizeof(padding));
+ }
+ else
+ {
+ printf("%s: write padding required\n",
+ slp->sl_xname);
+ }
+ }
+ else
+ {
+ len = slp->sl_scp.scp_datalen;
+ if ((ncv_io_control & NCV_WRITE_INTERRUPTS_DRIVEN) != 0)
+ {
+ if (len > ncv_data_write_bytes)
+ len = ncv_data_write_bytes;
+ }
+ ncv_pio_write(sc, slp->sl_scp.scp_data, len);
+ }
physio_proc_leave(pp);
break;
case DATA_IN_PHASE: /* data in */
SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
pp = physio_proc_enter(bp);
- ncv_pio_read(sc, slp->sl_scp.scp_data, slp->sl_scp.scp_datalen);
+ if (slp->sl_scp.scp_datalen <= 0)
+ {
+ if ((ireason & INTR_BS) == 0)
+ break;
+
+ if ((slp->sl_error & PDMAERR) == 0)
+ printf("%s: data overrun\n", slp->sl_xname);
+ slp->sl_error |= PDMAERR;
+
+ if ((slp->sl_flags & HW_READ_PADDING) != 0)
+ {
+ u_int8_t padding[NCV_PADDING_SIZE];
+
+ ncv_pio_read(sc, padding, sizeof(padding));
+ }
+ else
+ {
+ printf("%s: read padding required\n",
+ slp->sl_xname);
+ break;
+ }
+ }
+ else
+ {
+ len = slp->sl_scp.scp_datalen;
+ if ((ncv_io_control & NCV_READ_INTERRUPTS_DRIVEN) != 0)
+ {
+ if (len > ncv_data_read_bytes)
+ len = ncv_data_read_bytes;
+ }
+ ncv_pio_read(sc, slp->sl_scp.scp_data, len);
+ }
physio_proc_leave(pp);
break;
case COMMAND_PHASE: /* cmd out */
SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
if (scsi_low_cmd(slp, ti) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
ncvhw_fpush(iot, ioh,
@@ -1111,11 +1253,19 @@ ncvintr(arg)
SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
- len = scsi_low_msgout(slp, ti);
+ flags = SCSI_LOW_MSGOUT_UNIFY;
+ if (ti->ti_ophase != ti->ti_phase)
+ flags |= SCSI_LOW_MSGOUT_INIT;
+ len = scsi_low_msgout(slp, ti, flags);
+
+ if (len > 1 && slp->sl_atten == 0)
+ {
+ scsi_low_attention(slp);
+ }
+
ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len);
bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
- if (scsi_low_is_msgout_continue(ti) == 0)
- bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTATN);
+ SCSI_LOW_DEASSERT_ATN(slp);
break;
case MESSAGE_IN_PHASE: /* msg in */
@@ -1127,14 +1277,17 @@ ncvintr(arg)
sc->sc_compseq = 0;
if ((ireason & INTR_FC) && len == 2)
{
- ti->ti_status =
- bus_space_read_1(iot, ioh, cr0_sfifo);
+ regv = bus_space_read_1(iot, ioh, cr0_sfifo);
+ scsi_low_statusin(slp, ti, regv | derror);
len --;
}
else
{
- scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
- "compseq error");
+ slp->sl_error |= FATALIO;
+ scsi_low_assert_msg(slp, ti,
+ SCSI_LOW_MSG_ABORT, 1);
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+ cr0_cmd, CMD_MSGOK);
break;
}
}
@@ -1142,6 +1295,11 @@ ncvintr(arg)
{
bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
+ if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0)
+ {
+ if (ncv_catch_intr(sc) == 0)
+ goto again;
+ }
break;
}
@@ -1149,17 +1307,30 @@ ncvintr(arg)
{
regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
cr0_sfifo);
- scsi_low_msgin(slp, ti, regv);
+ if (scsi_low_msgin(slp, ti, regv | derror) == 0)
+ {
+ if (scsi_low_is_msgout_continue(ti, 0) != 0)
+ {
+ scsi_low_attention(slp);
+ }
+ }
bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd,
CMD_MSGOK);
+ if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0)
+ {
+ /* XXX:
+ * clear a pending interrupt and sync with
+ * a next interrupt!
+ */
+ ncv_catch_intr(sc);
+ }
}
else
{
- slp->sl_error |= MSGERR;
- printf("%s st %x ist %x\n\n", slp->sl_xname,
- status, ireason);
- scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
- "hw msgin error");
+ slp->sl_error |= FATALIO;
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd,
+ CMD_MSGOK);
}
break;
}
diff --git a/sys/dev/ncv/ncr53c500_pccard.c b/sys/dev/ncv/ncr53c500_pccard.c
index ed1b5d9..4a79f75 100644
--- a/sys/dev/ncv/ncr53c500_pccard.c
+++ b/sys/dev/ncv/ncr53c500_pccard.c
@@ -341,10 +341,13 @@ static void
ncv_card_unload(DEVPORT_PDEVICE devi)
{
struct ncv_softc *sc = DEVPORT_PDEVGET_SOFTC(devi);
+ intrmask_t s;
printf("%s: unload\n", sc->sc_sclow.sl_xname);
+ s = splcam();
scsi_low_deactivate((struct scsi_low_softc *)sc);
scsi_low_dettach(&sc->sc_sclow);
+ splx(s);
}
static int
@@ -384,6 +387,7 @@ ncvattach(DEVPORT_PDEVICE devi)
bus_addr_t offset = 0;
u_int iobase = DEVPORT_PDEVIOBASE(devi);
#endif
+ intrmask_t s;
char dvname[16]; /* SCSI_LOW_DVNAME_LEN */
strcpy(dvname, "ncv");
@@ -426,9 +430,9 @@ ncvattach(DEVPORT_PDEVICE devi)
slp->sl_hostid = NCV_HOSTID;
slp->sl_cfgflags = flags;
+ s = splcam();
ncvattachsubr(sc);
-
- sc->sc_ih = ncvintr;
+ splx(s);
return(NCVIOSZ);
}
diff --git a/sys/dev/ncv/ncr53c500hw.h b/sys/dev/ncv/ncr53c500hw.h
index e318959..5ea3a74 100644
--- a/sys/dev/ncv/ncr53c500hw.h
+++ b/sys/dev/ncv/ncr53c500hw.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $NecBSD: ncr53c500hw.h,v 1.6 1998/11/26 01:59:12 honda Exp $ */
+/* $NecBSD: ncr53c500hw.h,v 1.6.18.1 2001/06/08 06:27:44 honda Exp $ */
/* $NetBSD$ */
/*
@@ -44,16 +44,20 @@
struct ncv_hw {
/* configuration images */
- u_int8_t cfg1;
- u_int8_t cfg2;
- u_int8_t cfg3;
- u_int8_t cfg4;
- u_int8_t cfg5;
+ u_int8_t hw_cfg1;
+ u_int8_t hw_cfg2;
+ u_int8_t hw_cfg3;
+ u_int8_t hw_cfg4;
+ u_int8_t hw_cfg5;
/* synch */
- u_int8_t clk;
- u_int8_t mperiod;
- u_int8_t moffset;
+ u_int8_t hw_clk;
+ u_int8_t hw_mperiod;
+ u_int8_t hw_moffset;
+
+ /* cfg3 quirks */
+ u_int8_t hw_cfg3_fscsi;
+ u_int8_t hw_cfg3_fclk;
};
/* dvcfg */
diff --git a/sys/dev/ncv/ncr53c500hwtab.h b/sys/dev/ncv/ncr53c500hwtab.h
index c95787e9..7e16b9e 100644
--- a/sys/dev/ncv/ncr53c500hwtab.h
+++ b/sys/dev/ncv/ncr53c500hwtab.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $NecBSD: ncr53c500hwtab.h,v 1.2 1998/11/26 01:59:13 honda Exp $ */
+/* $NecBSD: ncr53c500hwtab.h,v 1.2.18.1 2001/06/08 06:27:44 honda Exp $ */
/* $NetBSD$ */
/*
@@ -34,14 +34,16 @@
*/
static struct ncv_hw ncv_template = {
- NCV_HOSTID,
- C2_FE | C2_SCSI2,
- C3_FCLK,
- C4_ANE,
- 0x80,
+ 0, /* CFG1 img */
+ C2_FE | C2_SCSI2, /* CFG2 img */
+ 0, /* CFG3 img */
+ C4_ANE, /* CFG4 img */
+ 0x80, /* CFG5 img */
- CLK_40M_F,
+ CLK_40M_F, /* clock */
+ 200 / 4, /* max period */
+ 15, /* max offset */
- 200 / 4,
- 15,
+ 0x10, /* CFG3_FSCSI bit */
+ 0x08, /* CFG3_FCLK bit */
};
diff --git a/sys/dev/ncv/ncr53c500reg.h b/sys/dev/ncv/ncr53c500reg.h
index ac39e1b..0296c5e 100644
--- a/sys/dev/ncv/ncr53c500reg.h
+++ b/sys/dev/ncv/ncr53c500reg.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $NecBSD: ncr53c500reg.h,v 1.5 1998/12/26 11:50:01 honda Exp $ */
+/* $NecBSD: ncr53c500reg.h,v 1.5.14.1 2001/06/08 06:27:44 honda Exp $ */
/* $NetBSD$ */
/*
@@ -85,11 +85,6 @@
/* cfg4 */
#define C4_ANE 0x04
-/* cfg3 */
-#define C3_NULL 0x00
-#define C3_FCLK 0x08 /* Fast SCSI */
-#define C3_FSCSI 0x10 /* Fast Clock (>25Mhz) */
-
/* cfg2 */
#define C2_SCSI2 0x08 /* SCSI-2 Enable */
#define C2_FE 0x40 /* Features Enable */
diff --git a/sys/dev/ncv/ncr53c500var.h b/sys/dev/ncv/ncr53c500var.h
index f040b17..21f4032 100644
--- a/sys/dev/ncv/ncr53c500var.h
+++ b/sys/dev/ncv/ncr53c500var.h
@@ -1,12 +1,12 @@
/* $FreeBSD$ */
-/* $NecBSD: ncr53c500var.h,v 1.11 1998/11/28 18:42:42 honda Exp $ */
+/* $NecBSD: ncr53c500var.h,v 1.11.18.1 2001/06/08 06:27:45 honda Exp $ */
/* $NetBSD$ */
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1995, 1996, 1997, 1998
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
- * Copyright (c) 1995, 1996, 1997, 1998
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
* Naofumi HONDA. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,18 +42,20 @@
struct ncv_softc {
struct scsi_low_softc sc_sclow; /* generic data */
+#ifdef __NetBSD__
bus_space_tag_t sc_iot;
bus_space_tag_t sc_memt;
bus_space_handle_t sc_ioh;
void *sc_ih;
- int sc_wc; /* weight counter */
- int sc_selstop; /* sel atn stop asserted */
- int sc_compseq; /* completion seq cmd asserted */
- int sc_tdatalen; /* temp xfer data len */
+#endif /* __NetBSD__ */
- struct ncv_hw sc_hw; /* hardware register images */
-#if defined (__FreeBSD__) && __FreeBSD_version >= 400001
+#ifdef __FreeBSD__
+ bus_space_tag_t sc_iot;
+ bus_space_tag_t sc_memt;
+ bus_space_handle_t sc_ioh;
+
+#if __FreeBSD_version >= 400001
int port_rid;
int port_rid_dmy;
int irq_rid;
@@ -62,19 +64,29 @@ struct ncv_softc {
struct resource *port_res_dmy;
struct resource *irq_res;
struct resource *mem_res;
+
void *ncv_intrhand;
-#endif
+#endif /* __FreeBSD_version__ */
+#endif /* __FreeBSD__ */
+
+ int sc_tmaxcnt;
+ int sc_selstop; /* sel atn stop asserted */
+ int sc_compseq; /* completion seq cmd asserted */
+ int sc_sdatalen; /* start datalen */
+ int sc_tdatalen; /* temp xfer data len */
+
+ struct ncv_hw sc_hw; /* hardware register images */
};
/*****************************************************************
- * Target information
+ * Lun information
*****************************************************************/
struct ncv_targ_info {
struct targ_info nti_ti;
- u_int8_t nti_reg_cfg3; /* cfg3 images per target */
- u_int8_t nti_reg_offset; /* synch offset register per target */
- u_int8_t nti_reg_period; /* synch period register per target */
+ u_int8_t nti_reg_cfg3; /* cfg3 images per lun */
+ u_int8_t nti_reg_offset; /* synch offset register per lun */
+ u_int8_t nti_reg_period; /* synch period register per lun */
};
/*****************************************************************
diff --git a/sys/dev/nsp/nsp.c b/sys/dev/nsp/nsp.c
index b10bdb3..a78dd34 100644
--- a/sys/dev/nsp/nsp.c
+++ b/sys/dev/nsp/nsp.c
@@ -1,13 +1,20 @@
/* $FreeBSD$ */
-/* $NecBSD: nsp.c,v 1.21 1999/07/23 21:00:05 honda Exp $ */
+/* $NecBSD: nsp.c,v 1.21.12.6 2001/06/29 06:27:52 honda Exp $ */
/* $NetBSD$ */
#define NSP_DEBUG
#define NSP_STATICS
+#define NSP_IO_CONTROL_FLAGS \
+ (NSP_READ_SUSPEND_IO | NSP_WRITE_SUSPEND_IO | \
+ NSP_READ_FIFO_INTERRUPTS | NSP_WRITE_FIFO_INTERRUPTS | \
+ NSP_USE_MEMIO | NSP_WAIT_FOR_SELECT)
/*
- * Copyright (c) 1998
+ * Copyright (c) 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
+ *
+ * Copyright (c) 1998, 1999, 2000, 2001
+ * Naofumi HONDA. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,19 +44,16 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/disklabel.h>
#if defined(__FreeBSD__) && __FreeBSD_version > 500001
#include <sys/bio.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>
-#include <vm/vm.h>
-
#ifdef __NetBSD__
+#include <sys/device.h>
#include <machine/bus.h>
#include <machine/intr.h>
@@ -68,8 +72,6 @@
#ifdef __FreeBSD__
#include <machine/clock.h>
-#define delay(time) DELAY(time)
-
#include <machine/cpu.h>
#include <machine/bus_pio.h>
#include <machine/bus_memio.h>
@@ -105,76 +107,101 @@ struct nsp_softc *nspdata[NNSP];
#define NSP_NTARGETS 8
#define NSP_NLUNS 8
-#define NSP_SELTIMEOUT 200
+#define NSP_MAX_DATA_SIZE (64 * 1024)
+#define NSP_SELTIMEOUT (200)
+#define NSP_DELAY_MAX (2 * 1000 * 1000)
+#define NSP_DELAY_INTERVAL (1)
+#define NSP_TIMER_1MS (1000 / 51)
/***************************************************
* DEBUG
***************************************************/
-#ifndef DDB
-#define Debugger() panic("should call debugger here (nsp.c)")
-#else /* ! DDB */
-#ifdef __FreeBSD__
-#define Debugger() Debugger("nsp")
-#endif /* __FreeBSD__ */
-#endif
-
#ifdef NSP_DEBUG
int nsp_debug;
#endif /* NSP_DEBUG */
#ifdef NSP_STATICS
struct nsp_statics {
+ int arbit_conflict_1;
+ int arbit_conflict_2;
+ int device_data_write;
+ int device_busy;
int disconnect;
int reselect;
int data_phase_bypass;
-} nsp_statics[NSP_NTARGETS];
+} nsp_statics;
#endif /* NSP_STATICS */
/***************************************************
- * ISA DEVICE STRUCTURE
+ * IO control
+ ***************************************************/
+#define NSP_READ_SUSPEND_IO 0x0001
+#define NSP_WRITE_SUSPEND_IO 0x0002
+#define NSP_USE_MEMIO 0x0004
+#define NSP_READ_FIFO_INTERRUPTS 0x0010
+#define NSP_WRITE_FIFO_INTERRUPTS 0x0020
+#define NSP_WAIT_FOR_SELECT 0x0100
+
+u_int nsp_io_control = NSP_IO_CONTROL_FLAGS;
+int nsp_read_suspend_bytes = DEV_BSIZE;
+int nsp_write_suspend_bytes = DEV_BSIZE;
+int nsp_read_interrupt_bytes = 4096;
+int nsp_write_interrupt_bytes = 4096;
+
+/***************************************************
+ * DEVICE STRUCTURE
***************************************************/
extern struct cfdriver nsp_cd;
/**************************************************************
* DECLARE
**************************************************************/
-#ifdef __NetBSD__
-extern int delaycount;
-#endif
-
-/* static */
-static void nsp_pio_read __P((struct nsp_softc *, struct targ_info *));
-static void nsp_pio_write __P((struct nsp_softc *, struct targ_info *));
-static int nsp_xfer __P((struct nsp_softc *, u_int8_t *, int, int));
+#define NSP_FIFO_ON 1
+#define NSP_FIFO_OFF 0
+static void nsp_pio_read __P((struct nsp_softc *, int));
+static void nsp_pio_write __P((struct nsp_softc *, int));
+static int nsp_xfer __P((struct nsp_softc *, u_int8_t *, int, int, int));
static int nsp_msg __P((struct nsp_softc *, struct targ_info *, u_int));
static int nsp_reselected __P((struct nsp_softc *));
-static __inline int nsp_disconnected __P((struct nsp_softc *, struct targ_info *));
-static __inline void nsp_pdma_end __P((struct nsp_softc *, struct targ_info *));
+static int nsp_disconnected __P((struct nsp_softc *, struct targ_info *));
+static void nsp_pdma_end __P((struct nsp_softc *, struct targ_info *));
static void nsphw_init __P((struct nsp_softc *));
-static int nsp_nexus __P((struct nsp_softc *, struct targ_info *));
+static int nsp_target_nexus_establish __P((struct nsp_softc *));
+static int nsp_lun_nexus_establish __P((struct nsp_softc *));
+static int nsp_ccb_nexus_establish __P((struct nsp_softc *));
static int nsp_world_start __P((struct nsp_softc *, int));
static int nsphw_start_selection __P((struct nsp_softc *sc, struct slccb *));
static void nsphw_bus_reset __P((struct nsp_softc *));
static void nsphw_attention __P((struct nsp_softc *));
static u_int nsp_fifo_count __P((struct nsp_softc *));
+static u_int nsp_request_count __P((struct nsp_softc *));
static int nsp_negate_signal __P((struct nsp_softc *, u_int8_t, u_char *));
static int nsp_expect_signal __P((struct nsp_softc *, u_int8_t, u_int8_t));
-static __inline void nsp_start_timer __P((struct nsp_softc *, int));
-static int nsp_dataphase_bypass __P((struct nsp_softc *, struct targ_info *));
-static void nsp_setup_fifo __P((struct nsp_softc *, int));
-static int nsp_targ_init __P((struct nsp_softc *, struct targ_info *));
+static void nsp_start_timer __P((struct nsp_softc *, int));
+static void nsp_setup_fifo __P((struct nsp_softc *, int, int, int));
+static int nsp_targ_init __P((struct nsp_softc *, struct targ_info *, int));
+static void nsphw_selection_done_and_expect_msgout __P((struct nsp_softc *));
+static void nsp_data_padding __P((struct nsp_softc *, int, u_int));
+static int nsp_timeout __P((struct nsp_softc *));
+static int nsp_read_fifo __P((struct nsp_softc *, int));
+static int nsp_write_fifo __P((struct nsp_softc *, int));
+static int nsp_phase_match __P((struct nsp_softc *, u_int8_t, u_int8_t));
+static int nsp_wait_interrupt __P((struct nsp_softc *));
struct scsi_low_funcs nspfuncs = {
SC_LOW_INIT_T nsp_world_start,
SC_LOW_BUSRST_T nsphw_bus_reset,
SC_LOW_TARG_INIT_T nsp_targ_init,
+ SC_LOW_LUN_INIT_T NULL,
SC_LOW_SELECT_T nsphw_start_selection,
- SC_LOW_NEXUS_T nsp_nexus,
+ SC_LOW_NEXUS_T nsp_lun_nexus_establish,
+ SC_LOW_NEXUS_T nsp_ccb_nexus_establish,
SC_LOW_ATTEN_T nsphw_attention,
SC_LOW_MSG_T nsp_msg,
+ SC_LOW_TIMEOUT_T nsp_timeout,
SC_LOW_POLL_T nspintr,
NULL,
@@ -217,35 +244,27 @@ nsp_expect_signal(sc, curphase, mask)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
- int wc = (sc->sc_wc >> 2);
+ int wc;
u_int8_t ph, isrc;
- int rv = -1;
- do
+ for (wc = 0; wc < NSP_DELAY_MAX / NSP_DELAY_INTERVAL; wc ++)
{
ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
- if (ph == 0xff) {
- rv = -1;
- break;
- }
+ if (ph == (u_int8_t) -1)
+ return -1;
+
isrc = bus_space_read_1(bst, bsh, nsp_irqsr);
- if (isrc & IRQSR_SCSI) {
- rv = 0;
- break;
- }
- if ((ph & mask) != 0 && (ph & SCBUSMON_PHMASK) == curphase) {
- rv = 1;
- break;
- }
- }
- while (wc -- > 0);
+ if (isrc & IRQSR_SCSI)
+ return 0;
+
+ if ((ph & mask) != 0 && (ph & SCBUSMON_PHMASK) == curphase)
+ return 1;
- if (wc <= 0) {
- printf("%s: nsp_expect_signal timeout\n", slp->sl_xname);
- rv = -1;
+ SCSI_LOW_DELAY(NSP_DELAY_INTERVAL);
}
- return rv;
+ printf("%s: nsp_expect_signal timeout\n", slp->sl_xname);
+ return -1;
}
static void
@@ -267,7 +286,7 @@ nsphw_init(sc)
nsp_cr_write_1(bst, bsh, NSPR_CLKDIVR, sc->sc_iclkdiv);
nsp_cr_write_1(bst, bsh, NSPR_SCIENR, sc->sc_icr);
- nsp_cr_write_1(bst, bsh, NSPR_PARITYR, 0);
+ nsp_cr_write_1(bst, bsh, NSPR_PARITYR, sc->sc_parr);
nsp_cr_write_1(bst, bsh, NSPR_PTCLRR,
PTCLRR_ACK | PTCLRR_REQ | PTCLRR_HOST | PTCLRR_RSS);
@@ -286,10 +305,10 @@ nsphw_init(sc)
nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, 0);
/* enable interrupts and ack them */
- nsp_cr_write_1(bst, bsh, NSPR_SCIENR, SCIENR_SCCHG | SCIENR_RESEL | SCIENR_RST);
+ nsp_cr_write_1(bst, bsh, NSPR_SCIENR, sc->sc_icr);
bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK);
- nsp_setup_fifo(sc, 0);
+ nsp_setup_fifo(sc, NSP_FIFO_OFF, SCSI_LOW_READ, 0);
}
/****************************************************
@@ -305,6 +324,7 @@ nsphw_attention(sc)
cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR)/* & ~SCBUSCR_ACK */;
nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr | SCBUSCR_ATN);
+ SCSI_LOW_DELAY(10);
}
static void
@@ -318,7 +338,7 @@ nsphw_bus_reset(sc)
bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_ALLMASK);
nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_RST);
- delay(100 * 1000); /* 100ms */
+ SCSI_LOW_DELAY(100 * 1000); /* 100ms */
nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, 0);
for (i = 0; i < 5; i ++)
(void) nsp_cr_read_1(bst, bsh, NSPR_IRQPHS);
@@ -326,16 +346,26 @@ nsphw_bus_reset(sc)
bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK);
}
-static __inline void
-nsp_start_timer(sc, time)
+static void
+nsphw_selection_done_and_expect_msgout(sc)
struct nsp_softc *sc;
- int time;
{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
- sc->sc_timer = time;
- nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, time);
+ /* clear ack counter */
+ sc->sc_cnt = 0;
+ nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK |
+ PTCLRR_REQ | PTCLRR_HOST);
+
+ /* deassert sel and assert atten */
+ sc->sc_seltout = 0;
+ nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, sc->sc_busc);
+ SCSI_LOW_DELAY(1);
+ nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
+ sc->sc_busc | SCBUSCR_ADIR | SCBUSCR_ACKEN);
+ SCSI_LOW_ASSERT_ATN(slp);
}
static int
@@ -348,58 +378,97 @@ nsphw_start_selection(sc, cb)
bus_space_handle_t bsh = sc->sc_ioh;
struct targ_info *ti = cb->ti;
register u_int8_t arbs, ph;
- int s, wc = sc->sc_wc;
+ int s, wc;
+
+ wc = sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
+ sc->sc_dataout_timeout = 0;
/* check bus free */
- if (slp->sl_disc > 0)
+ s = splhigh();
+ ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
+ if (ph != SCBUSMON_FREE)
{
- s = splhigh();
- ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
- if (ph != SCBUSMON_FREE)
- {
- splx(s);
- return SCSI_LOW_START_FAIL;
- }
splx(s);
+#ifdef NSP_STATICS
+ nsp_statics.arbit_conflict_1 ++;
+#endif /* NSP_STATICS */
+ return SCSI_LOW_START_FAIL;
}
/* start arbitration */
- SCSI_LOW_SETUP_PHASE(ti, PH_ARBSTART);
nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_EXEC);
+ splx(s);
+
+ SCSI_LOW_SETUP_PHASE(ti, PH_ARBSTART);
do
{
/* XXX: what a stupid chip! */
arbs = nsp_cr_read_1(bst, bsh, NSPR_ARBITS);
- delay(1);
+ SCSI_LOW_DELAY(1);
}
while ((arbs & (ARBITS_WIN | ARBITS_FAIL)) == 0 && wc -- > 0);
if ((arbs & ARBITS_WIN) == 0)
{
nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR);
+#ifdef NSP_STATICS
+ nsp_statics.arbit_conflict_2 ++;
+#endif /* NSP_STATICS */
return SCSI_LOW_START_FAIL;
}
/* assert select line */
SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
- scsi_low_arbit_win(slp, ti);
- delay(3);
+ scsi_low_arbit_win(slp);
+
+ s = splhigh();
+ SCSI_LOW_DELAY(3);
nsp_cr_write_1(bst, bsh, NSPR_DATA,
sc->sc_idbit | (1 << ti->ti_id));
nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
SCBUSCR_SEL | SCBUSCR_BSY | sc->sc_busc);
- delay(3);
+ SCSI_LOW_DELAY(3);
nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_SEL |
SCBUSCR_BSY | SCBUSCR_DOUT | sc->sc_busc);
nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR);
- delay(3);
+ SCSI_LOW_DELAY(3);
nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
SCBUSCR_SEL | SCBUSCR_DOUT | sc->sc_busc);
+ SCSI_LOW_DELAY(1);
- /* check selection timeout */
- nsp_start_timer(sc, 1000 / 51);
- sc->sc_seltout = 1;
+ if ((nsp_io_control & NSP_WAIT_FOR_SELECT) != 0)
+ {
+#define NSP_FIRST_SEL_WAIT 300
+#define NSP_SEL_CHECK_INTERVAL 10
+
+ /* wait for a selection response */
+ for (wc = 0; wc < NSP_FIRST_SEL_WAIT / NSP_SEL_CHECK_INTERVAL;
+ wc ++)
+ {
+ ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
+ if ((ph & SCBUSMON_BSY) == 0)
+ {
+ SCSI_LOW_DELAY(NSP_SEL_CHECK_INTERVAL);
+ continue;
+ }
+
+ SCSI_LOW_DELAY(1);
+ ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
+ if ((ph & SCBUSMON_BSY) != 0)
+ {
+ nsphw_selection_done_and_expect_msgout(sc);
+ splx(s);
+
+ SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
+ return SCSI_LOW_START_OK;
+ }
+ }
+ }
+ splx(s);
+ /* check a selection timeout */
+ nsp_start_timer(sc, NSP_TIMER_1MS);
+ sc->sc_seltout = 1;
return SCSI_LOW_START_OK;
}
@@ -409,24 +478,24 @@ nsp_world_start(sc, fdone)
int fdone;
{
struct scsi_low_softc *slp = &sc->sc_sclow;
-#ifdef __FreeBSD__
- intrmask_t s;
- s = splcam();
-#endif
sc->sc_cnt = 0;
sc->sc_seltout = 0;
+
if ((slp->sl_cfgflags & CFG_NOATTEN) == 0)
sc->sc_busc = SCBUSCR_ATN;
else
sc->sc_busc = 0;
+
+ if ((slp->sl_cfgflags & CFG_NOPARITY) == 0)
+ sc->sc_parr = PARITYR_ENABLE | PARITYR_CLEAR;
+ else
+ sc->sc_parr = 0;
+
sc->sc_icr = (SCIENR_SCCHG | SCIENR_RESEL | SCIENR_RST);
nsphw_init(sc);
scsi_low_bus_reset(slp);
-#ifdef __FreeBSD__
- splx(s);
-#endif
SOFT_INTR_REQUIRED(slp);
return 0;
@@ -460,10 +529,22 @@ nsp_msg(sc, ti, msg)
struct targ_info *ti;
u_int msg;
{
+ bus_space_tag_t bst = sc->sc_iot;
+ bus_space_handle_t bsh = sc->sc_ioh;
struct ncp_synch_data *sdp;
struct nsp_targ_info *nti = (void *) ti;
u_int period, offset;
- int i;
+ int i, error;
+
+ if ((msg & SCSI_LOW_MSG_WIDE) != 0)
+ {
+ if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
+ {
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
+ return EINVAL;
+ }
+ return 0;
+ }
if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
return 0;
@@ -491,29 +572,52 @@ nsp_msg(sc, ti, msg)
ti->ti_maxsynch.offset = 0;
nti->nti_reg_syncr = 0;
nti->nti_reg_ackwidth = 0;
- return EINVAL;
+ error = EINVAL;
+ }
+ else
+ {
+ nti->nti_reg_syncr = (sdp->chip_period << SYNCR_PERS) |
+ (offset & SYNCR_OFFM);
+ nti->nti_reg_ackwidth = sdp->ack_width;
+ error = 0;
}
- nti->nti_reg_syncr = (sdp->chip_period << SYNCR_PERS) |
- (offset & SYNCR_OFFM);
- nti->nti_reg_ackwidth = sdp->ack_width;
- return 0;
+ nsp_cr_write_1(bst, bsh, NSPR_SYNCR, nti->nti_reg_syncr);
+ nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, nti->nti_reg_ackwidth);
+ return error;
}
static int
-nsp_targ_init(sc, ti)
+nsp_targ_init(sc, ti, action)
struct nsp_softc *sc;
struct targ_info *ti;
+ int action;
{
struct nsp_targ_info *nti = (void *) ti;
- ti->ti_maxsynch.period = 200 / 4;
- ti->ti_maxsynch.offset = 15;
- nti->nti_reg_syncr = 0;
- nti->nti_reg_ackwidth = 0;
+ if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
+ {
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
+ ti->ti_maxsynch.period = 100 / 4;
+ ti->ti_maxsynch.offset = 15;
+ nti->nti_reg_syncr = 0;
+ nti->nti_reg_ackwidth = 0;
+ }
return 0;
}
+static void
+nsp_start_timer(sc, time)
+ struct nsp_softc *sc;
+ int time;
+{
+ bus_space_tag_t bst = sc->sc_iot;
+ bus_space_handle_t bsh = sc->sc_ioh;
+
+ sc->sc_timer = time;
+ nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, time);
+}
+
/**************************************************************
* General probe attach
**************************************************************/
@@ -550,20 +654,13 @@ nspattachsubr(sc)
printf("\n");
-#ifdef __FreeBSD__
- sc->sc_wc = 0x2000 * 2000; /* XXX need calibration */
-#else
- sc->sc_wc = delaycount * 2000; /* 2 sec */
-#endif
sc->sc_idbit = (1 << slp->sl_hostid);
+ slp->sl_flags |= HW_READ_PADDING;
slp->sl_funcs = &nspfuncs;
- if (sc->sc_memh != NULL)
- sc->sc_xmode = NSP_MID_SMIT;
- else
- sc->sc_xmode = NSP_PIO;
+ sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
- (void) scsi_low_attach(slp, 2, NSP_NTARGETS, NSP_NLUNS,
- sizeof(struct nsp_targ_info));
+ (void) scsi_low_attach(slp, 0, NSP_NTARGETS, NSP_NLUNS,
+ sizeof(struct nsp_targ_info), 0);
}
/**************************************************************
@@ -577,57 +674,110 @@ nsp_fifo_count(sc)
bus_space_handle_t bsh = sc->sc_ioh;
u_int count;
- nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT);
+ nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_RSS_ACK | PTCLRR_PT);
count = bus_space_read_1(bst, bsh, nsp_datar);
count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 8);
count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 16);
return count;
}
-static void
-nsp_setup_fifo(sc, on)
+static u_int
+nsp_request_count(sc)
struct nsp_softc *sc;
- int on;
{
- struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
+ u_int count;
+
+ nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_RSS_REQ | PTCLRR_PT);
+ count = bus_space_read_1(bst, bsh, nsp_datar);
+ count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 8);
+ count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 16);
+ return count;
+}
+
+static void
+nsp_setup_fifo(sc, on, direction, datalen)
+ struct nsp_softc *sc;
+ int on;
+ int direction;
+ int datalen;
+{
u_int8_t xfermode;
- if (on != 0)
- xfermode = XFERMR_XEN | XFERMR_FIFOEN;
- else
- xfermode = 0;
+ sc->sc_suspendio = 0;
+ if (on == NSP_FIFO_OFF)
+ {
+ xfermode = XFERMR_IO8;
+ goto out;
+ }
- if ((slp->sl_scp.scp_datalen % DEV_BSIZE) != 0)
+ /* check if suspend io OK ? */
+ if (datalen > 0)
{
- sc->sc_mask = 0;
- xfermode |= XFERMR_IO8;
+ if (direction == SCSI_LOW_READ)
+ {
+ if ((nsp_io_control & NSP_READ_SUSPEND_IO) != 0 &&
+ (datalen % nsp_read_suspend_bytes) == 0)
+ sc->sc_suspendio = nsp_read_suspend_bytes;
+ }
+ else
+ {
+ if ((nsp_io_control & NSP_WRITE_SUSPEND_IO) != 0 &&
+ (datalen % nsp_write_suspend_bytes) == 0)
+ sc->sc_suspendio = nsp_write_suspend_bytes;
+ }
+ }
+
+ /* determine a transfer type */
+ if (datalen < DEV_BSIZE || (datalen & 3) != 0)
+ {
+ if (sc->sc_memh != NULL &&
+ (nsp_io_control & NSP_USE_MEMIO) != 0)
+ xfermode = XFERMR_XEN | XFERMR_MEM8;
+ else
+ xfermode = XFERMR_XEN | XFERMR_IO8;
}
else
{
- sc->sc_mask = 3;
- if (sc->sc_xmode == NSP_MID_SMIT)
- xfermode |= XFERMR_MEM32;
+ if (sc->sc_memh != NULL &&
+ (nsp_io_control & NSP_USE_MEMIO) != 0)
+ xfermode = XFERMR_XEN | XFERMR_MEM32;
else
- xfermode |= XFERMR_IO32;
+ xfermode = XFERMR_XEN | XFERMR_IO32;
+
+ if (sc->sc_suspendio > 0)
+ xfermode |= XFERMR_FIFOEN;
}
+out:
sc->sc_xfermr = xfermode;
- nsp_cr_write_1(bst, bsh, NSPR_XFERMR, sc->sc_xfermr);
+ nsp_cr_write_1(sc->sc_iot, sc->sc_ioh, NSPR_XFERMR, sc->sc_xfermr);
}
-static __inline void
+static void
nsp_pdma_end(sc, ti)
struct nsp_softc *sc;
struct targ_info *ti;
{
struct scsi_low_softc *slp = &sc->sc_sclow;
- struct slccb *cb = ti->ti_nexus;
+ struct slccb *cb = slp->sl_Qnexus;
u_int len = 0, cnt;
+ sc->sc_dataout_timeout = 0;
slp->sl_flags &= ~HW_PDMASTART;
- nsp_setup_fifo(sc, 0);
+ nsp_setup_fifo(sc, NSP_FIFO_OFF, SCSI_LOW_READ, 0);
+ if ((sc->sc_icr & SCIENR_FIFO) != 0)
+ {
+ sc->sc_icr &= ~SCIENR_FIFO;
+ nsp_cr_write_1(sc->sc_iot, sc->sc_ioh, NSPR_SCIENR, sc->sc_icr);
+ }
+
+ if (cb == NULL)
+ {
+ slp->sl_error |= PDMAERR;
+ return;
+ }
if (ti->ti_phase == PH_DATA)
{
@@ -635,7 +785,8 @@ nsp_pdma_end(sc, ti)
if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
{
len = sc->sc_cnt - cnt;
- if (slp->sl_scp.scp_datalen + len <=
+ if (sc->sc_cnt >= cnt &&
+ slp->sl_scp.scp_datalen + len <=
cb->ccb_scp.scp_datalen)
{
slp->sl_scp.scp_data -= len;
@@ -651,14 +802,17 @@ nsp_pdma_end(sc, ti)
}
else if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
{
- if (sc->sc_cnt != cnt)
+ if (sc->sc_cnt != cnt ||
+ sc->sc_cnt > cb->ccb_scp.scp_datalen)
{
slp->sl_error |= PDMAERR;
- printf("%s: data read count error %x != %x\n",
- slp->sl_xname, sc->sc_cnt, cnt);
+ printf("%s: data read count error %x != %x (%x)\n",
+ slp->sl_xname, sc->sc_cnt, cnt,
+ cb->ccb_scp.scp_datalen);
}
}
sc->sc_cnt = cnt;
+ scsi_low_data_finish(slp);
}
else
{
@@ -669,131 +823,397 @@ nsp_pdma_end(sc, ti)
}
#define RFIFO_CRIT 64
-#define WFIFO_CRIT 64
+#define WFIFO_CRIT 32
static void
-nsp_pio_read(sc, ti)
+nsp_data_padding(sc, direction, count)
struct nsp_softc *sc;
- struct targ_info *ti;
+ int direction;
+ u_int count;
+{
+ bus_space_tag_t bst = sc->sc_iot;
+ bus_space_handle_t bsh = sc->sc_ioh;
+
+ if (count > NSP_MAX_DATA_SIZE)
+ count = NSP_MAX_DATA_SIZE;
+
+ nsp_cr_write_1(bst, bsh, NSPR_XFERMR, XFERMR_XEN | XFERMR_IO8);
+ if (direction == SCSI_LOW_READ)
+ {
+ while (count -- > 0)
+ (void) bus_space_read_1(bst, bsh, nsp_fifodr);
+ }
+ else
+ {
+ while (count -- > 0)
+ (void) bus_space_write_1(bst, bsh, nsp_fifodr, 0);
+ }
+ nsp_cr_write_1(bst, bsh, NSPR_XFERMR, sc->sc_xfermr);
+}
+
+static int
+nsp_read_fifo(sc, suspendio)
+ struct nsp_softc *sc;
+ int suspendio;
{
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
- int tout = sc->sc_wc;
- u_int res, ocount, mask = sc->sc_mask;
- u_int8_t stat, fstat;
+ u_int res;
- slp->sl_flags |= HW_PDMASTART;
- ocount = sc->sc_cnt;
+ res = nsp_fifo_count(sc);
+ if (res == sc->sc_cnt)
+ return 0;
- while (slp->sl_scp.scp_datalen > 0 && tout -- > 0)
+#ifdef NSP_DEBUG
+ if (res < sc->sc_cnt || res == (u_int) -1)
{
- stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
- stat &= SCBUSMON_PHMASK;
- res = nsp_fifo_count(sc) - ocount;
+ printf("%s: strange fifo ack count 0x%x < 0x%x\n",
+ slp->sl_xname, res, sc->sc_cnt);
+ return 0;
+ }
+#endif /* NSP_DEBUG */
+
+ res = res - sc->sc_cnt;
+ if (res > slp->sl_scp.scp_datalen)
+ {
+ if ((slp->sl_error & PDMAERR) == 0)
+ {
+ printf("%s: data overrun 0x%x > 0x%x\n",
+ slp->sl_xname, res, slp->sl_scp.scp_datalen);
+ }
+
+ slp->sl_error |= PDMAERR;
+ slp->sl_scp.scp_datalen = 0;
+
+ if ((slp->sl_flags & HW_READ_PADDING) == 0)
+ {
+ printf("%s: read padding required\n", slp->sl_xname);
+ return 0;
+ }
+
+ nsp_data_padding(sc, SCSI_LOW_READ, res);
+ sc->sc_cnt += res;
+ return 1; /* padding start */
+ }
+
+ if (suspendio > 0 && slp->sl_scp.scp_datalen >= suspendio)
+ res = suspendio;
+
+ if ((sc->sc_xfermr & (XFERMR_MEM32 | XFERMR_MEM8)) != 0)
+ {
+ if ((sc->sc_xfermr & XFERMR_MEM32) != 0)
+ {
+ res &= ~3;
+ bus_space_read_region_4(sc->sc_memt, sc->sc_memh, 0,
+ (u_int32_t *) slp->sl_scp.scp_data, res >> 2);
+ }
+ else
+ {
+ bus_space_read_region_1(sc->sc_memt, sc->sc_memh, 0,
+ (u_int8_t *) slp->sl_scp.scp_data, res);
+ }
+ }
+ else
+ {
+ if ((sc->sc_xfermr & XFERMR_IO32) != 0)
+ {
+ res &= ~3;
+ bus_space_read_multi_4(bst, bsh, nsp_fifodr,
+ (u_int32_t *) slp->sl_scp.scp_data, res >> 2);
+ }
+ else
+ {
+ bus_space_read_multi_1(bst, bsh, nsp_fifodr,
+ (u_int8_t *) slp->sl_scp.scp_data, res);
+ }
+ }
+
+ if (nsp_cr_read_1(bst, bsh, NSPR_PARITYR) & PARITYR_PE)
+ {
+ nsp_cr_write_1(bst, bsh, NSPR_PARITYR,
+ PARITYR_ENABLE | PARITYR_CLEAR);
+ scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_ERROR, 1);
+ }
+
+ slp->sl_scp.scp_data += res;
+ slp->sl_scp.scp_datalen -= res;
+ sc->sc_cnt += res;
+ return 0;
+}
+
+static int
+nsp_write_fifo(sc, suspendio)
+ struct nsp_softc *sc;
+ int suspendio;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ bus_space_tag_t bst = sc->sc_iot;
+ bus_space_handle_t bsh = sc->sc_ioh;
+ u_int res;
+ register u_int8_t stat;
+
+ if (suspendio > 0)
+ {
+#ifdef NSP_DEBUG
+ if ((slp->sl_scp.scp_datalen % WFIFO_CRIT) != 0)
+ {
+ printf("%s: strange write length 0x%x\n",
+ slp->sl_xname, slp->sl_scp.scp_datalen);
+ }
+#endif /* NSP_DEBUG */
+ res = slp->sl_scp.scp_datalen % suspendio;
if (res == 0)
{
- if (stat == PHASE_DATAIN)
- continue;
- break;
+ res = suspendio;
}
+ }
+ else
+ {
+ res = WFIFO_CRIT;
+ }
- fstat = bus_space_read_1(bst, bsh, nsp_fifosr);
- if ((fstat & FIFOSR_FULLEMP) == 0 && stat == PHASE_DATAIN)
- continue;
+ if (res > slp->sl_scp.scp_datalen)
+ res = slp->sl_scp.scp_datalen;
- if (res > slp->sl_scp.scp_datalen)
- break;
+ /* XXX: reconfirm! */
+ stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON) & SCBUSMON_PHMASK;
+ if (stat != PHASE_DATAOUT)
+ return 0;
- if (res >= NSP_BUFFER_SIZE)
- res = NSP_BUFFER_SIZE;
+ if ((sc->sc_xfermr & (XFERMR_MEM32 | XFERMR_MEM8)) != 0)
+ {
+ if ((sc->sc_xfermr & XFERMR_MEM32) != 0)
+ {
+ bus_space_write_region_4(sc->sc_memt, sc->sc_memh, 0,
+ (u_int32_t *) slp->sl_scp.scp_data, res >> 2);
+ }
+ else
+ {
+ bus_space_write_region_1(sc->sc_memt, sc->sc_memh, 0,
+ (u_int8_t *) slp->sl_scp.scp_data, res);
+ }
+ }
+ else
+ {
+ if ((sc->sc_xfermr & XFERMR_IO32) != 0)
+ {
+ bus_space_write_multi_4(bst, bsh, nsp_fifodr,
+ (u_int32_t *) slp->sl_scp.scp_data, res >> 2);
+ }
else
- res &= ~mask;
+ {
+ bus_space_write_multi_1(bst, bsh, nsp_fifodr,
+ (u_int8_t *) slp->sl_scp.scp_data, res);
+ }
+ }
+
+ slp->sl_scp.scp_datalen -= res;
+ slp->sl_scp.scp_data += res;
+ sc->sc_cnt += res;
+ return 0;
+}
+
+static int
+nsp_wait_interrupt(sc)
+ struct nsp_softc *sc;
+{
+ bus_space_tag_t bst = sc->sc_iot;
+ bus_space_handle_t bsh = sc->sc_ioh;
+ int tout;
+ register u_int8_t isrc;
+
+ for (tout = 0; tout < DEV_BSIZE / 10; tout ++)
+ {
+ isrc = bus_space_read_1(bst, bsh, nsp_irqsr);
+ if ((isrc & (IRQSR_SCSI | IRQSR_FIFO)) != 0)
+ {
+ if ((isrc & IRQSR_FIFO) != 0)
+ {
+ bus_space_write_1(bst, bsh,
+ nsp_irqcr, IRQCR_FIFOCL);
+ }
+ return 1;
+ }
+ SCSI_LOW_DELAY(1);
+ }
+ return 0;
+}
+
+static void
+nsp_pio_read(sc, suspendio)
+ struct nsp_softc *sc;
+ int suspendio;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ bus_space_tag_t bst = sc->sc_iot;
+ bus_space_handle_t bsh = sc->sc_ioh;
+ int tout, padding, datalen;
+ register u_int8_t stat, fstat;
+
+ padding = 0;
+ tout = sc->sc_tmaxcnt;
+ slp->sl_flags |= HW_PDMASTART;
+ datalen = slp->sl_scp.scp_datalen;
- if (sc->sc_xfermr & XFERMR_MEM32)
+ReadLoop:
+ while (1)
+ {
+ stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
+ if (stat == (u_int8_t) -1)
+ return;
+
+ /* out of data phase */
+ if ((stat & SCBUSMON_PHMASK) != PHASE_DATAIN)
{
- bus_space_read_region_4(sc->sc_memt,
- sc->sc_memh,
- 0,
- (u_int32_t *) slp->sl_scp.scp_data,
- res >> 2);
+ nsp_read_fifo(sc, 0);
+ return;
+ }
+
+ /* data phase */
+ fstat = bus_space_read_1(bst, bsh, nsp_fifosr);
+ if ((fstat & FIFOSR_FULLEMP) != 0)
+ {
+ if ((sc->sc_icr & SCIENR_FIFO) != 0)
+ {
+ bus_space_write_1(bst, bsh, nsp_irqcr,
+ IRQCR_FIFOCL);
+ }
+
+ if (suspendio > 0)
+ {
+ padding |= nsp_read_fifo(sc, suspendio);
+ }
+ else
+ {
+ padding |= nsp_read_fifo(sc, 0);
+ }
+
+ if ((sc->sc_icr & SCIENR_FIFO) != 0)
+ break;
}
else
{
- if (mask != 0)
- bus_space_read_multi_4(bst, bsh, nsp_fifodr,
- (u_int32_t *) slp->sl_scp.scp_data,
- res >> 2);
- else
- bus_space_read_multi_1(bst, bsh, nsp_fifodr,
- (u_int8_t *) slp->sl_scp.scp_data,
- res);
+ if (padding == 0 && slp->sl_scp.scp_datalen <= 0)
+ return;
+
+ if ((sc->sc_icr & SCIENR_FIFO) != 0)
+ break;
+
+ SCSI_LOW_DELAY(1);
}
- slp->sl_scp.scp_data += res;
- slp->sl_scp.scp_datalen -= res;
- ocount += res;
+ if ((-- tout) <= 0)
+ {
+ printf("%s: nsp_pio_read: timeout\n", slp->sl_xname);
+ return;
+ }
}
- sc->sc_cnt = ocount;
- if (tout <= 0)
- printf("%s pio read timeout\n", slp->sl_xname);
+
+ if (slp->sl_scp.scp_datalen > 0 &&
+ slp->sl_scp.scp_datalen > datalen - nsp_read_interrupt_bytes)
+ {
+ if (nsp_wait_interrupt(sc) != 0)
+ goto ReadLoop;
+ }
}
static void
-nsp_pio_write(sc, ti)
+nsp_pio_write(sc, suspendio)
struct nsp_softc *sc;
- struct targ_info *ti;
+ int suspendio;
{
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
- u_int res, ocount, mask = sc->sc_mask;
- int tout = sc->sc_wc;
- register u_int8_t stat;
+ u_int rcount, acount;
+ int tout, datalen;
+ register u_int8_t stat, fstat;
- ocount = sc->sc_cnt;
+ tout = sc->sc_tmaxcnt;
slp->sl_flags |= HW_PDMASTART;
- while (slp->sl_scp.scp_datalen > 0 && tout -- > 0)
+ datalen = slp->sl_scp.scp_datalen;
+
+WriteLoop:
+ while (1)
{
- stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
- stat &= SCBUSMON_PHMASK;
+ stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON) & SCBUSMON_PHMASK;
if (stat != PHASE_DATAOUT)
- break;
+ return;
- res = ocount - nsp_fifo_count(sc);
- if (res > 0)
- continue;
-
- res = (slp->sl_scp.scp_datalen > WFIFO_CRIT) ? WFIFO_CRIT :
- slp->sl_scp.scp_datalen;
+ if (slp->sl_scp.scp_datalen <= 0)
+ {
+ if (sc->sc_dataout_timeout == 0)
+ sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ;
+ return;
+ }
- if (sc->sc_xfermr & XFERMR_MEM32)
+ fstat = bus_space_read_1(bst, bsh, nsp_fifosr);
+ if ((fstat & FIFOSR_FULLEMP) != 0)
{
- bus_space_write_region_4(sc->sc_memt,
- sc->sc_memh,
- 0,
- (u_int32_t *) slp->sl_scp.scp_data,
- res >> 2);
+ if ((sc->sc_icr & SCIENR_FIFO) != 0)
+ {
+ bus_space_write_1(bst, bsh, nsp_irqcr,
+ IRQCR_FIFOCL);
+ }
+
+ if (suspendio > 0)
+ {
+ /* XXX:IMPORTANT:
+ * To avoid timeout of pcmcia bus
+ * (not scsi bus!), we should check
+ * the scsi device sends us request
+ * signals, which means the scsi device
+ * is ready to recieve data without
+ * heavy delays.
+ */
+ acount = nsp_fifo_count(sc);
+ rcount = nsp_request_count(sc);
+ if (rcount <= acount)
+ {
+ nsp_write_fifo(sc, 0);
+#ifdef NSP_STATICS
+ nsp_statics.device_busy ++;
+#endif /* NSP_STATICS */
+ }
+ else
+ {
+ nsp_write_fifo(sc, suspendio);
+#ifdef NSP_STATICS
+ nsp_statics.device_data_write ++;
+#endif /* NSP_STATICS */
+ }
+ }
+ else
+ {
+ nsp_write_fifo(sc, 0);
+ }
+
+ if ((sc->sc_icr & SCIENR_FIFO) != 0)
+ break;
}
else
{
- if (mask != 0)
- bus_space_write_multi_4(bst, bsh, nsp_fifodr,
- (u_int32_t *) slp->sl_scp.scp_data, res >> 2);
- else
- bus_space_write_multi_1(bst, bsh, nsp_fifodr,
- (u_int8_t *) slp->sl_scp.scp_data, res);
+ if ((sc->sc_icr & SCIENR_FIFO) != 0)
+ break;
+
+ SCSI_LOW_DELAY(1);
}
- slp->sl_scp.scp_datalen -= res;
- slp->sl_scp.scp_data += res;
- ocount += res;
+ if ((-- tout) <= 0)
+ {
+ printf("%s: nsp_pio_write: timeout\n", slp->sl_xname);
+ return;
+ }
}
- sc->sc_cnt = ocount;
- if (tout <= 0)
- printf("%s pio write timeout\n", slp->sl_xname);
+ if (slp->sl_scp.scp_datalen > 0 &&
+ slp->sl_scp.scp_datalen > datalen - nsp_write_interrupt_bytes)
+ {
+ if (nsp_wait_interrupt(sc) != 0)
+ goto WriteLoop;
+ }
}
static int
@@ -805,46 +1225,46 @@ nsp_negate_signal(sc, mask, s)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
- int wc = (sc->sc_wc >> 2);
+ int wc;
u_int8_t regv;
- do
+ for (wc = 0; wc < NSP_DELAY_MAX / NSP_DELAY_INTERVAL; wc ++)
{
regv = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
- if (regv == 0xff)
- break;
+ if (regv == (u_int8_t) -1)
+ return -1;
+ if ((regv & mask) == 0)
+ return 1;
+ SCSI_LOW_DELAY(NSP_DELAY_INTERVAL);
}
- while ((regv & mask) != 0 && (-- wc) > 0);
-
- if (wc <= 0)
- printf("%s: %s singla off timeout \n", slp->sl_xname, s);
- return 0;
+ printf("%s: %s nsp_negate_signal timeout\n", slp->sl_xname, s);
+ return -1;
}
static int
-nsp_xfer(sc, buf, len, phase)
+nsp_xfer(sc, buf, len, phase, clear_atn)
struct nsp_softc *sc;
u_int8_t *buf;
int len;
int phase;
+ int clear_atn;
{
- struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
- int ptr, rv, atn;
+ int ptr, rv;
- atn = (scsi_low_is_msgout_continue(slp->sl_nexus) != 0);
for (ptr = 0; len > 0; len --, ptr ++)
{
rv = nsp_expect_signal(sc, phase, SCBUSMON_REQ);
if (rv <= 0)
goto out;
- if (len == 1 && atn == 0)
+ if (len == 1 && clear_atn != 0)
{
nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
SCBUSCR_ADIR | SCBUSCR_ACKEN);
+ SCSI_LOW_DEASSERT_ATN(&sc->sc_sclow);
}
if (phase & SCBUSMON_IO)
@@ -862,41 +1282,6 @@ out:
return len;
}
-static int
-nsp_dataphase_bypass(sc, ti)
- struct nsp_softc *sc;
- struct targ_info *ti;
-{
- struct scsi_low_softc *slp = &sc->sc_sclow;
- struct slccb *cb = ti->ti_nexus;
- u_int cnt;
-
- if (slp->sl_scp.scp_direction != SCSI_LOW_READ ||
- (slp->sl_scp.scp_datalen % DEV_BSIZE) == 0)
- return 0;
-
- cnt = nsp_fifo_count(sc);
- if (sc->sc_cnt == cnt)
- return 0;
- if (cnt >= DEV_BSIZE)
- return EINVAL;
-
- if (cb == NULL)
- return 0;
-
- /*
- * XXX: NSP_QUIRK
- * Data phase skip only occures in case of SCSI_LOW_READ.
- */
- SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
- nsp_pio_read(sc, ti);
- nsp_pdma_end(sc, ti);
-#ifdef NSP_STATICS
- nsp_statics[ti->ti_id].data_phase_bypass ++;
-#endif /* NSP_STATICS */
- return 0;
-}
-
/**************************************************************
* disconnect & reselect (HW low)
**************************************************************/
@@ -919,28 +1304,39 @@ nsp_reselected(sc)
nsp_negate_signal(sc, SCBUSMON_SEL, "reselect<SEL>");
- cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) & ~(SCBUSCR_BSY | SCBUSCR_ATN);
+ cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR);
+ cr &= ~(SCBUSCR_BSY | SCBUSCR_ATN);
+ nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
+ cr |= SCBUSCR_ADIR | SCBUSCR_ACKEN;
nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
- nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr | SCBUSCR_ADIR | SCBUSCR_ACKEN);
#ifdef NSP_STATICS
- nsp_statics[sid].reselect ++;
+ nsp_statics.reselect ++;
#endif /* NSP_STATCIS */
return EJUSTRETURN;
}
-static __inline int
+static int
nsp_disconnected(sc, ti)
struct nsp_softc *sc;
struct targ_info *ti;
{
struct scsi_low_softc *slp = &sc->sc_sclow;
+ bus_space_tag_t bst = sc->sc_iot;
+ bus_space_handle_t bsh = sc->sc_ioh;
+ nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK |
+ PTCLRR_REQ | PTCLRR_HOST);
+ if ((sc->sc_icr & SCIENR_FIFO) != 0)
+ {
+ sc->sc_icr &= ~SCIENR_FIFO;
+ nsp_cr_write_1(bst, bsh, NSPR_SCIENR, sc->sc_icr);
+ }
+ sc->sc_cnt = 0;
+ sc->sc_dataout_timeout = 0;
#ifdef NSP_STATICS
- if (slp->sl_msgphase == MSGPH_DISC)
- nsp_statics[ti->ti_id].disconnect ++;
+ nsp_statics.disconnect ++;
#endif /* NSP_STATICS */
-
scsi_low_disconnected(slp, ti);
return 1;
}
@@ -948,10 +1344,10 @@ nsp_disconnected(sc, ti)
/**************************************************************
* SEQUENCER
**************************************************************/
-static void nspmsg __P((struct nsp_softc *, u_char *, u_int8_t, u_int8_t, u_int8_t));
+static void nsp_error __P((struct nsp_softc *, u_char *, u_int8_t, u_int8_t, u_int8_t));
static void
-nspmsg(sc, s, isrc, ph, irqphs)
+nsp_error(sc, s, isrc, ph, irqphs)
struct nsp_softc *sc;
u_char *s;
u_int8_t isrc, ph, irqphs;
@@ -964,25 +1360,86 @@ nspmsg(sc, s, isrc, ph, irqphs)
}
static int
-nsp_nexus(sc, ti)
+nsp_target_nexus_establish(sc)
struct nsp_softc *sc;
- struct targ_info *ti;
{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
+ struct targ_info *ti = slp->sl_Tnexus;
struct nsp_targ_info *nti = (void *) ti;
/* setup synch transfer registers */
nsp_cr_write_1(bst, bsh, NSPR_SYNCR, nti->nti_reg_syncr);
nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, nti->nti_reg_ackwidth);
+ /* setup pdma fifo (minimum) */
+ nsp_setup_fifo(sc, NSP_FIFO_ON, SCSI_LOW_READ, 0);
+ return 0;
+}
+
+static int
+nsp_lun_nexus_establish(sc)
+ struct nsp_softc *sc;
+{
+
+ return 0;
+}
+
+static int
+nsp_ccb_nexus_establish(sc)
+ struct nsp_softc *sc;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ struct slccb *cb = slp->sl_Qnexus;
+
+ sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
+
/* setup pdma fifo */
- nsp_setup_fifo(sc, 1);
+ nsp_setup_fifo(sc, NSP_FIFO_ON,
+ slp->sl_scp.scp_direction, slp->sl_scp.scp_datalen);
+
+ if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
+ {
+ if (sc->sc_suspendio > 0 &&
+ (nsp_io_control & NSP_READ_FIFO_INTERRUPTS) != 0)
+ {
+ sc->sc_icr |= SCIENR_FIFO;
+ nsp_cr_write_1(sc->sc_iot, sc->sc_ioh,
+ NSPR_SCIENR, sc->sc_icr);
+ }
+ }
+ else
+ {
+ if (sc->sc_suspendio > 0 &&
+ (nsp_io_control & NSP_WRITE_FIFO_INTERRUPTS) != 0)
+ {
+ sc->sc_icr |= SCIENR_FIFO;
+ nsp_cr_write_1(sc->sc_iot, sc->sc_ioh,
+ NSPR_SCIENR, sc->sc_icr);
+ }
+ }
+ return 0;
+}
+
+static int
+nsp_phase_match(sc, phase, stat)
+ struct nsp_softc *sc;
+ u_int8_t phase;
+ u_int8_t stat;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+
+ if ((stat & SCBUSMON_PHMASK) != phase)
+ {
+ printf("%s: phase mismatch 0x%x != 0x%x\n",
+ slp->sl_xname, (u_int) phase, (u_int) stat);
+ return EINVAL;
+ }
+
+ if ((stat & SCBUSMON_REQ) == 0)
+ return EINVAL;
- /* clear ack counter */
- sc->sc_cnt = 0;
- nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK |
- PTCLRR_REQ | PTCLRR_HOST);
return 0;
}
@@ -997,6 +1454,7 @@ nspintr(arg)
struct targ_info *ti;
struct physio_proc *pp;
struct buf *bp;
+ u_int derror, flags;
int len, rv;
u_int8_t isrc, ph, irqphs, cr, regv;
@@ -1008,7 +1466,7 @@ nspintr(arg)
bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_IRQDIS);
isrc = bus_space_read_1(bst, bsh, nsp_irqsr);
- if (isrc == 0xff || (isrc & IRQSR_MASK) == 0)
+ if (isrc == (u_int8_t) -1 || (isrc & IRQSR_MASK) == 0)
{
bus_space_write_1(bst, bsh, nsp_irqcr, 0);
return 0;
@@ -1036,13 +1494,26 @@ nspintr(arg)
sc->sc_timer = 0;
}
- if ((isrc & IRQSR_MASK) == IRQSR_TIMER && sc->sc_seltout == 0)
+ /* check a timer interrupt */
+ regv = 0;
+ if ((isrc & IRQSR_TIMER) != 0)
{
- bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_TIMERCL);
- return 1;
+ if ((isrc & IRQSR_MASK) == IRQSR_TIMER && sc->sc_seltout == 0)
+ {
+ bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_TIMERCL);
+ return 1;
+ }
+ regv |= IRQCR_TIMERCL;
}
- bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_TIMERCL | IRQCR_FIFOCL);
+ /* check a fifo interrupt */
+ if ((isrc & IRQSR_FIFO) != 0)
+ {
+ regv |= IRQCR_FIFOCL;
+ }
+
+ /* OK. enable all interrupts */
+ bus_space_write_1(bst, bsh, nsp_irqcr, regv);
/*******************************************
* debug section
@@ -1050,10 +1521,12 @@ nspintr(arg)
#ifdef NSP_DEBUG
if (nsp_debug)
{
- nspmsg(sc, "current status", isrc, ph, irqphs);
+ nsp_error(sc, "current status", isrc, ph, irqphs);
scsi_low_print(slp, NULL);
+#ifdef DDB
if (nsp_debug > 1)
- Debugger();
+ SCSI_LOW_DEBUGGER("nsp");
+#endif /* DDB */
}
#endif /* NSP_DEBUG */
@@ -1083,10 +1556,10 @@ nspintr(arg)
/*******************************************
* nexus check
*******************************************/
- if ((ti = slp->sl_nexus) == NULL)
+ if ((ti = slp->sl_Tnexus) == NULL)
{
/* unknown scsi phase changes */
- nspmsg(sc, "unknown scsi phase changes", isrc, ph, irqphs);
+ nsp_error(sc, "unknown scsi phase changes", isrc, ph, irqphs);
return 0;
}
@@ -1105,63 +1578,93 @@ nspintr(arg)
return nsp_disconnected(sc, ti);
}
sc->sc_seltout ++;
- nsp_start_timer(sc, 1000 / 51);
+ nsp_start_timer(sc, NSP_TIMER_1MS);
return 1;
}
- /* attention assert */
- sc->sc_seltout = 0;
SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
- nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, sc->sc_busc);
- delay(1);
- nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
- sc->sc_busc | SCBUSCR_ADIR | SCBUSCR_ACKEN);
-
- SCSI_LOW_TARGET_ASSERT_ATN(ti);
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
+ nsphw_selection_done_and_expect_msgout(sc);
return 1;
+ case PH_SELECTED:
+ if ((isrc & IRQSR_SCSI) == 0)
+ return 1;
+
+ nsp_target_nexus_establish(sc);
+ break;
+
case PH_RESEL:
+ if ((isrc & IRQSR_SCSI) == 0)
+ return 1;
+
+ nsp_target_nexus_establish(sc);
if ((ph & SCBUSMON_PHMASK) != PHASE_MSGIN)
{
+ printf("%s: unexpected phase after reselect\n",
+ slp->sl_xname);
+ slp->sl_error |= FATALIO;
scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
return 1;
}
- /* fall */
+ break;
+
+ case PH_DATA:
+ if ((isrc & IRQSR_SCSI) != 0)
+ break;
+ if ((isrc & IRQSR_FIFO) != 0)
+ {
+ if (NSP_IS_PHASE_DATA(ph) == 0)
+ return 1;
+ irqphs = (ph & IRQPHS_PHMASK);
+ break;
+ }
+ return 1;
default:
- if ((isrc & (IRQSR_SCSI | IRQSR_FIFO)) == 0)
+ if ((isrc & IRQSR_SCSI) == 0)
return 1;
break;
}
/*******************************************
- * scsi seq
+ * data phase control
*******************************************/
if (slp->sl_flags & HW_PDMASTART)
- nsp_pdma_end(sc, ti);
+ {
+ if ((isrc & IRQSR_SCSI) != 0 &&
+ NSP_IS_IRQPHS_DATA(irqphs) == 0)
+ {
+ if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
+ nsp_pio_read(sc, 0);
+ nsp_pdma_end(sc, ti);
+ }
+ }
- /* normal disconnect */
+ /*******************************************
+ * scsi seq
+ *******************************************/
if (slp->sl_msgphase != 0 && (irqphs & IRQPHS_LBF) != 0)
return nsp_disconnected(sc, ti);
/* check unexpected bus free state */
if (ph == 0)
{
- nspmsg(sc, "unexpected bus free", isrc, ph, irqphs);
+ nsp_error(sc, "unexpected bus free", isrc, ph, irqphs);
return nsp_disconnected(sc, ti);
}
/* check normal scsi phase */
- switch (ph & SCBUSMON_PHMASK)
+ switch (irqphs & IRQPHS_PHMASK)
{
- case PHASE_CMD:
- if ((ph & SCBUSMON_REQ) == 0)
+ case IRQPHS_CMD:
+ if (nsp_phase_match(sc, PHASE_CMD, ph) != 0)
return 1;
SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
if (scsi_low_cmd(slp, ti) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR);
for (len = 0; len < slp->sl_scp.scp_cmdlen; len ++)
@@ -1171,39 +1674,67 @@ nspintr(arg)
nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR | CMDCR_EXEC);
break;
- case PHASE_DATAOUT:
+ case IRQPHS_DATAOUT:
SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
pp = physio_proc_enter(bp);
- nsp_pio_write(sc, ti);
+ nsp_pio_write(sc, sc->sc_suspendio);
physio_proc_leave(pp);
break;
- case PHASE_DATAIN:
+ case IRQPHS_DATAIN:
SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
pp = physio_proc_enter(bp);
- nsp_pio_read(sc, ti);
+ nsp_pio_read(sc, sc->sc_suspendio);
physio_proc_leave(pp);
break;
- case PHASE_STATUS:
- nsp_dataphase_bypass(sc, ti);
- if ((ph & SCBUSMON_REQ) == 0)
+ case IRQPHS_STATUS:
+ if (nsp_phase_match(sc, PHASE_STATUS, ph) != 0)
return 1;
SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
- ti->ti_status = nsp_cr_read_1(bst, bsh, NSPR_DATAACK);
+ regv = nsp_cr_read_1(bst, bsh, NSPR_DATA);
+ if (nsp_cr_read_1(bst, bsh, NSPR_PARITYR) & PARITYR_PE)
+ {
+ nsp_cr_write_1(bst, bsh, NSPR_PARITYR,
+ PARITYR_ENABLE | PARITYR_CLEAR);
+ derror = SCSI_LOW_DATA_PE;
+ }
+ else
+ derror = 0;
+
+ /* assert ACK */
+ cr = SCBUSCR_ACK | nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR);
+ nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
+
+ if (scsi_low_statusin(slp, ti, derror | regv) != 0)
+ {
+ scsi_low_attention(slp);
+ }
+
+ /* check REQ nagated */
+ nsp_negate_signal(sc, SCBUSMON_REQ, "statin<REQ>");
+
+ /* deassert ACK */
+ cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) & (~SCBUSCR_ACK);
+ nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
break;
- case PHASE_MSGOUT:
- if ((ph & SCBUSMON_REQ) == 0)
- goto timerout;
+ case IRQPHS_MSGOUT:
+ if (nsp_phase_match(sc, PHASE_MSGOUT, ph) != 0)
+ return 1;
+#ifdef NSP_MSGOUT_SERIALIZE
/*
* XXX: NSP QUIRK
* NSP invoke interrupts only in the case of scsi phase changes,
@@ -1213,13 +1744,20 @@ nspintr(arg)
rv = len = 16;
do {
SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
+ flags = (ti->ti_ophase != ti->ti_phase) ?
+ SCSI_LOW_MSGOUT_INIT : 0;
+ len = scsi_low_msgout(slp, ti, flags);
- len = scsi_low_msgout(slp, ti);
- if (nsp_xfer(sc, ti->ti_msgoutstr, len, PHASE_MSGOUT))
+ if (len > 1 && slp->sl_atten == 0)
{
- scsi_low_assert_msg(slp, ti,
- SCSI_LOW_MSG_RESET, 0);
- nspmsg(sc, "MSGOUT: xfer short",
+ scsi_low_attention(slp);
+ }
+
+ if (nsp_xfer(sc, ti->ti_msgoutstr, len, PHASE_MSGOUT,
+ slp->sl_clear_atten) != 0)
+ {
+ slp->sl_error |= FATALIO;
+ nsp_error(sc, "MSGOUT: xfer short",
isrc, ph, irqphs);
}
@@ -1227,14 +1765,31 @@ nspintr(arg)
rv = nsp_expect_signal(sc, PHASE_MSGOUT, SCBUSMON_REQ);
}
while (rv > 0 && len -- > 0);
- break;
- case PHASE_MSGIN:
- nsp_dataphase_bypass(sc, ti);
- if ((ph & SCBUSMON_REQ) == 0)
- goto timerout;
+#else /* !NSP_MSGOUT_SERIALIZE */
+ SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
+ flags = SCSI_LOW_MSGOUT_UNIFY;
+ if (ti->ti_ophase != ti->ti_phase)
+ flags |= SCSI_LOW_MSGOUT_INIT;
+ len = scsi_low_msgout(slp, ti, flags);
+
+ if (len > 1 && slp->sl_atten == 0)
+ {
+ scsi_low_attention(slp);
+ }
- SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
+ if (nsp_xfer(sc, ti->ti_msgoutstr, len, PHASE_MSGOUT,
+ slp->sl_clear_atten) != 0)
+ {
+ nsp_error(sc, "MSGOUT: xfer short", isrc, ph, irqphs);
+ }
+
+#endif /* !NSP_MSGOUT_SERIALIZE */
+ break;
+
+ case IRQPHS_MSGIN:
+ if (nsp_phase_match(sc, PHASE_MSGIN, ph) != 0)
+ return 1;
/*
* XXX: NSP QUIRK
@@ -1244,20 +1799,39 @@ nspintr(arg)
*/
rv = len = 16;
do {
+ SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
+
/* read a data */
regv = nsp_cr_read_1(bst, bsh, NSPR_DATA);
+ if (nsp_cr_read_1(bst, bsh, NSPR_PARITYR) & PARITYR_PE)
+ {
+ nsp_cr_write_1(bst, bsh,
+ NSPR_PARITYR,
+ PARITYR_ENABLE | PARITYR_CLEAR);
+ derror = SCSI_LOW_DATA_PE;
+ }
+ else
+ {
+ derror = 0;
+ }
/* assert ack */
- cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR);
- cr |= SCBUSCR_ACK;
+ cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) | SCBUSCR_ACK;
nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
- nsp_negate_signal(sc, SCBUSMON_REQ, "msgin<REQ>");
- scsi_low_msgin(slp, ti, regv);
+ if (scsi_low_msgin(slp, ti, regv | derror) == 0)
+ {
+ if (scsi_low_is_msgout_continue(ti, 0) != 0)
+ {
+ scsi_low_attention(slp);
+ }
+ }
+
+ /* check REQ nagated */
+ nsp_negate_signal(sc, SCBUSMON_REQ, "msgin<REQ>");
/* deassert ack */
- cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR);
- cr &= ~SCBUSCR_ACK;
+ cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) & (~SCBUSCR_ACK);
nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
/* catch a next signal */
@@ -1266,15 +1840,85 @@ nspintr(arg)
while (rv > 0 && len -- > 0);
break;
- case PHASE_SEL:
default:
- nspmsg(sc, "unknown scsi phase", isrc, ph, irqphs);
+ slp->sl_error |= FATALIO;
+ nsp_error(sc, "unknown scsi phase", isrc, ph, irqphs);
break;
}
return 1;
+#if 0
timerout:
- nsp_start_timer(sc, 1000 / 102);
+ nsp_start_timer(sc, NSP_TIMER_1MS);
+ return 0;
+#endif
+}
+
+static int
+nsp_timeout(sc)
+ struct nsp_softc *sc;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int tout;
+ u_int8_t ph, regv;
+
+ if (slp->sl_Tnexus == NULL)
+ return 0;
+
+ ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON);
+ switch (ph & SCBUSMON_PHMASK)
+ {
+ case PHASE_DATAOUT:
+ if (sc->sc_dataout_timeout == 0)
+ break;
+
+ /* check a fifo empty */
+ regv = bus_space_read_1(iot, ioh, nsp_fifosr);
+ if ((regv & FIFOSR_FULLEMP) == 0)
+ break;
+ bus_space_write_1(iot, ioh, nsp_irqcr, IRQCR_FIFOCL);
+
+ /* check still requested */
+ ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON);
+ if ((ph & SCBUSMON_REQ) == 0)
+ break;
+ /* check timeout */
+ if ((-- sc->sc_dataout_timeout) > 0)
+ break;
+
+ slp->sl_error |= PDMAERR;
+ if ((slp->sl_flags & HW_WRITE_PADDING) == 0)
+ {
+ printf("%s: write padding required\n", slp->sl_xname);
+ break;
+ }
+
+ tout = NSP_DELAY_MAX;
+ while (tout -- > 0)
+ {
+ ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON);
+ if ((ph & SCBUSMON_PHMASK) != PHASE_DATAOUT)
+ break;
+ regv = bus_space_read_1(iot, ioh, nsp_fifosr);
+ if ((regv & FIFOSR_FULLEMP) == 0)
+ {
+ SCSI_LOW_DELAY(1);
+ continue;
+ }
+
+ bus_space_write_1(iot, ioh, nsp_irqcr, IRQCR_FIFOCL);
+ nsp_data_padding(sc, SCSI_LOW_WRITE, 32);
+ }
+ ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON);
+ if ((ph & SCBUSMON_PHMASK) == PHASE_DATAOUT)
+ sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ;
+ break;
+
+ default:
+ break;
+ }
return 0;
}
diff --git a/sys/dev/nsp/nsp_pccard.c b/sys/dev/nsp/nsp_pccard.c
index 3bc2428..a0b4556 100644
--- a/sys/dev/nsp/nsp_pccard.c
+++ b/sys/dev/nsp/nsp_pccard.c
@@ -318,10 +318,13 @@ static void
nsp_card_unload(DEVPORT_PDEVICE devi)
{
struct nsp_softc *sc = DEVPORT_PDEVGET_SOFTC(devi);
+ intrmask_t s;
printf("%s: unload\n",sc->sc_sclow.sl_xname);
+ s = splcam();
scsi_low_deactivate((struct scsi_low_softc *)sc);
scsi_low_dettach(&sc->sc_sclow);
+ splx(s);
}
static int
@@ -352,6 +355,7 @@ nspattach(DEVPORT_PDEVICE devi)
struct scsi_low_softc *slp;
u_int32_t flags = DEVPORT_PDEVFLAGS(devi);
u_int iobase = DEVPORT_PDEVIOBASE(devi);
+ intrmask_t s;
char dvname[16];
strcpy(dvname,"nsp");
@@ -406,9 +410,9 @@ nspattach(DEVPORT_PDEVICE devi)
slp->sl_hostid = NSP_HOSTID;
slp->sl_cfgflags = flags;
+ s = splcam();
nspattachsubr(sc);
-
- sc->sc_ih = nspintr;
+ splx(s);
return(NSP_IOSIZE);
}
diff --git a/sys/dev/nsp/nspreg.h b/sys/dev/nsp/nspreg.h
index 9912a13..3bfcd96 100644
--- a/sys/dev/nsp/nspreg.h
+++ b/sys/dev/nsp/nspreg.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $NecBSD: nspreg.h,v 1.4 1999/04/15 01:35:55 kmatsuda Exp $ */
+/* $NecBSD: nspreg.h,v 1.4.14.3 2001/06/29 06:27:53 honda Exp $ */
/* $NetBSD$ */
/*
@@ -92,6 +92,7 @@
#define IRQPHS_RSEL 0x20
#define IRQPHS_FIFO 0x40
#define IRQPHS_RST 0x80
+#define IRQPHS_PHMASK (IRQPHS_LCD | IRQPHS_LMSG | IRQPHS_LIO)
#define NSPR_TIMERCNT 0x17
@@ -125,6 +126,9 @@
#define ARBITS_RESEL 0x08
#define NSPR_PARITYR 0x1B /* (W/R) */
+#define PARITYR_ENABLE 0x01
+#define PARITYR_CLEAR 0x02
+#define PARITYR_PE 0x02
#define NSPR_CMDCR 0x1C /* (W) */
#define CMDCR_PTCLR 0x01
@@ -139,6 +143,9 @@
#define PTCLRR_REQ 0x04
#define PTCLRR_HOST 0x08
#define PTCLRR_RSS 0x30
+#define PTCLRR_RSS_ACK 0x00
+#define PTCLRR_RSS_REQ 0x10
+#define PTCLRR_RSS_HOST 0x20
#define NSPR_XFERCR 0x1E /* (R) */
@@ -185,6 +192,12 @@
#define SCBUSMON_PHMASK \
(SCBUSMON_SEL | SCBUSMON_CD | SCBUSMON_MSG | SCBUSMON_IO)
+/* Data phase */
+#define NSP_IS_PHASE_DATA(ph) \
+ ((((ph) & SCBUSMON_PHMASK) & ~SCBUSMON_IO) == 0)
+#define NSP_IS_IRQPHS_DATA(ph) \
+ ((((ph) & IRQPHS_PHMASK) & ~SCBUSMON_IO) == 0)
+
/* SCSI phase */
#define PHASE_CMD (SCBUSMON_CMD & SCBUSMON_PHMASK)
#define PHASE_DATAIN (SCBUSMON_DATAIN & SCBUSMON_PHMASK)
@@ -194,6 +207,13 @@
#define PHASE_MSGOUT (SCBUSMON_MSGOUT & SCBUSMON_PHMASK)
#define PHASE_SEL (SCBUSMON_SEL | SCBUSMON_IO)
+#define IRQPHS_CMD (IRQPHS_LCD)
+#define IRQPHS_DATAIN (IRQPHS_LIO)
+#define IRQPHS_DATAOUT (0)
+#define IRQPHS_STATUS (IRQPHS_LCD | IRQPHS_LIO)
+#define IRQPHS_MSGIN (IRQPHS_LCD | IRQPHS_LMSG | IRQPHS_LIO)
+#define IRQPHS_MSGOUT (IRQPHS_LCD | IRQPHS_LMSG)
+
/* Size */
#define NSP_MEMSIZE NBPG
#define NSP_IOSIZE 16
diff --git a/sys/dev/nsp/nspvar.h b/sys/dev/nsp/nspvar.h
index 41912d3..e7a348101c 100644
--- a/sys/dev/nsp/nspvar.h
+++ b/sys/dev/nsp/nspvar.h
@@ -1,11 +1,14 @@
/* $FreeBSD$ */
-/* $NecBSD: nspvar.h,v 1.7 1999/04/15 01:35:55 kmatsuda Exp $ */
+/* $NecBSD: nspvar.h,v 1.7.14.5 2001/06/29 06:27:54 honda Exp $ */
/* $NetBSD$ */
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1998
+ * Copyright (c) 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
+ *
+ * Copyright (c) 1998, 1999, 2000, 2001
+ * Naofumi HONDA. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -40,48 +43,57 @@
struct nsp_softc {
struct scsi_low_softc sc_sclow; /* generic data */
+#ifdef __NetBSD__
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_space_tag_t sc_memt;
bus_space_handle_t sc_memh;
void *sc_ih;
- int sc_wc;
+#endif /* __NetBSD__ */
+#ifdef __FreeBSD__
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ bus_space_tag_t sc_memt;
+ bus_space_handle_t sc_memh;
+
+#if __FreeBSD_version >= 400001
+ int port_rid;
+ int irq_rid;
+ int mem_rid;
+ struct resource *port_res;
+ struct resource *irq_res;
+ struct resource *mem_res;
+
+ void *nsp_intrhand;
+#endif /* __FreeBSD_version */
+#endif /* __FreeBSD__ */
+
+ int sc_tmaxcnt; /* timeout count */
int sc_seltout; /* selection timeout counter */
int sc_timer; /* timer start */
- int sc_xmode;
-#define NSP_HIGH_SMIT 2 /* write address data mode */
-#define NSP_MID_SMIT 1 /* mem access */
-#define NSP_PIO 0 /* io access */
+ int sc_suspendio; /* SMIT: data suspendio bytes */
+ u_int8_t sc_xfermr; /* SMIT: fifo control reg */
+ int sc_dataout_timeout; /* data out timeout counter */
u_int sc_idbit; /* host id bit pattern */
- u_int sc_mask; /* bus width mask */
u_int sc_cnt; /* fifo R/W count (host) */
+
u_int8_t sc_iclkdiv; /* scsi chip clock divisor */
u_int8_t sc_clkdiv; /* asic chip clock divisor */
- u_int8_t sc_xfermr; /* fifo control reg */
u_int8_t sc_icr; /* interrupt control reg */
u_int8_t sc_busc; /* busc registers */
- u_long sc_ringp; /* data buffer ring pointer */
-#if defined (__FreeBSD__) && __FreeBSD_version >= 400001
- int port_rid;
- int irq_rid;
- int mem_rid;
- struct resource *port_res;
- struct resource *irq_res;
- struct resource *mem_res;
- void *nsp_intrhand;
-#endif
+ u_int8_t sc_parr; /* parity control register */
};
/*****************************************************************
- * Target information
+ * Lun information
*****************************************************************/
struct nsp_targ_info {
- struct targ_info nti_ti; /* generic target info */
+ struct targ_info nti_ti; /* generic lun info */
u_int8_t nti_reg_syncr; /* sync registers per devices */
u_int8_t nti_reg_ackwidth; /* ackwidth per devices */
diff --git a/sys/dev/stg/tmc18c30.c b/sys/dev/stg/tmc18c30.c
index b331dd3..930aa40 100644
--- a/sys/dev/stg/tmc18c30.c
+++ b/sys/dev/stg/tmc18c30.c
@@ -1,15 +1,16 @@
/* $FreeBSD$ */
-/* $NecBSD: tmc18c30.c,v 1.28 1999/07/23 21:00:06 honda Exp $ */
+/* $NecBSD: tmc18c30.c,v 1.28.12.3 2001/06/19 04:35:48 honda Exp $ */
/* $NetBSD$ */
#define STG_DEBUG
#define STG_STATICS
+#define STG_IO_CONTROL_FLAGS (STG_FIFO_INTERRUPTS | STG_WAIT_FOR_SELECT)
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1996, 1997, 1998, 1999
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
- * Copyright (c) 1996, 1997, 1998, 1999
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001
* Naofumi HONDA. All rights reserved.
* Copyright (c) 1996, 1997, 1998, 1999
* Kouichi Matsuda. All rights reserved.
@@ -42,19 +43,16 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/disklabel.h>
#if defined(__FreeBSD__) && __FreeBSD_version >= 500001
#include <sys/bio.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>
-#include <vm/vm.h>
-
#ifdef __NetBSD__
+#include <sys/device.h>
#include <machine/bus.h>
#include <machine/intr.h>
@@ -73,8 +71,6 @@
#ifdef __FreeBSD__
#include <machine/clock.h>
-#define delay(time) DELAY(time)
-
#include <machine/cpu.h>
#include <machine/bus_pio.h>
#include <machine/bus.h>
@@ -106,10 +102,14 @@ struct stg_softc *stgdata[NSTG];
/* For the 512 fifo type: change below */
#define TMC18C30_FIFOSZ 0x800
-#define TMC18C30_FCB 1
-
+#define TMC18C30_FCBSZ 0x200
#define TMC18C50_FIFOSZ 0x2000
-#define TMC18C50_FCB 2
+#define TMC18C50_FCBSZ 0x400
+
+#define STG_MAX_DATA_SIZE (64 * 1024)
+#define STG_DELAY_MAX (2 * 1000 * 1000)
+#define STG_DELAY_INTERVAL (1)
+#define STG_DELAY_SELECT_POLLING_MAX (5 * 1000 * 1000)
/***************************************************
* PARAMS
@@ -120,47 +120,42 @@ struct stg_softc *stgdata[NSTG];
/***************************************************
* DEBUG
***************************************************/
-#ifndef DDB
-#define Debugger() panic("should call debugger here (tmc18c30.c)")
-#else /* ! DDB */
-#ifdef __FreeBSD__
-#define Debugger() Debugger("stg")
-#endif /* __FreeBSD__ */
-#endif
-
#ifdef STG_DEBUG
int stg_debug;
#endif /* STG_DEBUG */
#ifdef STG_STATICS
struct stg_statics {
+ int arbit_fail_0;
+ int arbit_fail_1;
int disconnect;
int reselect;
- int sprious_arbit_fail_0;
- int sprious_arbit_fail_1;
- int sprious_arbit_fail_2;
-} stg_statics[STG_NTARGETS];
+} stg_statics;
#endif /* STG_STATICS */
/***************************************************
- * ISA DEVICE STRUCTURE
+ * IO control flags
+ ***************************************************/
+#define STG_FIFO_INTERRUPTS 0x0001
+#define STG_WAIT_FOR_SELECT 0x0100
+
+int stg_io_control = STG_IO_CONTROL_FLAGS;
+
+/***************************************************
+ * DEVICE STRUCTURE
***************************************************/
extern struct cfdriver stg_cd;
/**************************************************************
* DECLARE
**************************************************************/
-#ifdef __NetBSD__
-extern int delaycount;
-#endif
-
/* static */
-static void stg_pio_read __P((struct stg_softc *, struct targ_info *));
-static void stg_pio_write __P((struct stg_softc *, struct targ_info *));
-static int stg_xfer __P((struct stg_softc *, u_int8_t *, int, int));
+static void stg_pio_read __P((struct stg_softc *, struct targ_info *, u_int));
+static void stg_pio_write __P((struct stg_softc *, struct targ_info *, u_int));
+static int stg_xfer __P((struct stg_softc *, u_int8_t *, int, int, int));
static int stg_msg __P((struct stg_softc *, struct targ_info *, u_int));
static int stg_reselected __P((struct stg_softc *));
-static __inline int stg_disconnected __P((struct stg_softc *, struct targ_info *));
+static int stg_disconnected __P((struct stg_softc *, struct targ_info *));
static __inline void stg_pdma_end __P((struct stg_softc *, struct targ_info *));
static int stghw_select_targ_wait __P((struct stg_softc *, int));
static int stghw_check __P((struct stg_softc *));
@@ -171,28 +166,35 @@ static int stg_world_start __P((struct stg_softc *, int));
static int stghw_start_selection __P((struct stg_softc *sc, struct slccb *));
static void stghw_bus_reset __P((struct stg_softc *));
static void stghw_attention __P((struct stg_softc *));
-static int stg_nexus __P((struct stg_softc *, struct targ_info *));
-static int stg_targ_init __P((struct stg_softc *, struct targ_info *));
+static int stg_target_nexus_establish __P((struct stg_softc *));
+static int stg_lun_nexus_establish __P((struct stg_softc *));
+static int stg_ccb_nexus_establish __P((struct stg_softc *));
+static int stg_targ_init __P((struct stg_softc *, struct targ_info *, int));
static __inline void stghw_bcr_write_1 __P((struct stg_softc *, u_int8_t));
+static int stg_timeout __P((struct stg_softc *));
+static void stg_selection_done_and_expect_msgout __P((struct stg_softc *));
struct scsi_low_funcs stgfuncs = {
SC_LOW_INIT_T stg_world_start,
SC_LOW_BUSRST_T stghw_bus_reset,
SC_LOW_TARG_INIT_T stg_targ_init,
+ SC_LOW_LUN_INIT_T NULL,
SC_LOW_SELECT_T stghw_start_selection,
- SC_LOW_NEXUS_T stg_nexus,
+ SC_LOW_NEXUS_T stg_lun_nexus_establish,
+ SC_LOW_NEXUS_T stg_ccb_nexus_establish,
SC_LOW_ATTEN_T stghw_attention,
SC_LOW_MSG_T stg_msg,
+ SC_LOW_TIMEOUT_T stg_timeout,
SC_LOW_POLL_T stgintr,
NULL,
};
/****************************************************
- * scsi low interface
+ * hwfuncs
****************************************************/
static __inline void
stghw_bcr_write_1(sc, bcv)
@@ -204,6 +206,101 @@ stghw_bcr_write_1(sc, bcv)
sc->sc_busimg = bcv;
}
+static int
+stghw_check(sc)
+ struct stg_softc *sc;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int fcbsize, fcb;
+ u_int16_t lsb, msb;
+
+ lsb = bus_space_read_1(iot, ioh, tmc_idlsb);
+ msb = bus_space_read_1(iot, ioh, tmc_idmsb);
+ switch (msb << 8 | lsb)
+ {
+ case 0x6127:
+ /* TMCCHIP_1800 not supported. (it's my policy) */
+ sc->sc_chip = TMCCHIP_1800;
+ return EINVAL;
+
+ case 0x60e9:
+ if (bus_space_read_1(iot, ioh, tmc_cfg2) & 0x02)
+ {
+ sc->sc_chip = TMCCHIP_18C30;
+ sc->sc_fsz = TMC18C30_FIFOSZ;
+ fcbsize = TMC18C30_FCBSZ;
+ }
+ else
+ {
+ sc->sc_chip = TMCCHIP_18C50;
+ sc->sc_fsz = TMC18C50_FIFOSZ;
+ fcbsize = TMC18C50_FCBSZ;
+ }
+ break;
+
+ default:
+ sc->sc_chip = TMCCHIP_UNK;
+ return ENODEV;
+ }
+
+ sc->sc_fcRinit = FCTL_INTEN;
+ sc->sc_fcWinit = FCTL_PARENB | FCTL_INTEN;
+
+ if (slp->sl_cfgflags & CFG_NOATTEN)
+ sc->sc_imsg = 0;
+ else
+ sc->sc_imsg = BCTL_ATN;
+ sc->sc_busc = BCTL_BUSEN;
+
+ sc->sc_wthold = fcbsize + 256;
+ sc->sc_rthold = fcbsize - 256;
+ sc->sc_maxwsize = sc->sc_fsz;
+
+ fcb = fcbsize / (sc->sc_fsz / 16);
+ sc->sc_icinit = ICTL_CD | ICTL_SEL | ICTL_ARBIT | fcb;
+ return 0;
+}
+
+static void
+stghw_init(sc)
+ struct stg_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ bus_space_write_1(iot, ioh, tmc_ictl, 0);
+ stghw_bcr_write_1(sc, BCTL_BUSFREE);
+ bus_space_write_1(iot, ioh, tmc_fctl,
+ sc->sc_fcRinit | FCTL_CLRFIFO | FCTL_CLRINT);
+ bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
+ bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
+
+ bus_space_write_1(iot, ioh, tmc_ssctl, 0);
+}
+
+static int
+stg_targ_init(sc, ti, action)
+ struct stg_softc *sc;
+ struct targ_info *ti;
+ int action;
+{
+ struct stg_targ_info *sti = (void *) ti;
+
+ if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
+ {
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
+ ti->ti_maxsynch.period = 0;
+ ti->ti_maxsynch.offset = 0;
+ sti->sti_reg_synch = 0;
+ }
+ return 0;
+}
+
+/****************************************************
+ * scsi low interface
+ ****************************************************/
static void
stghw_attention(sc)
struct stg_softc *sc;
@@ -212,6 +309,7 @@ stghw_attention(sc)
sc->sc_busc |= BCTL_ATN;
sc->sc_busimg |= BCTL_ATN;
bus_space_write_1(sc->sc_iot, sc->sc_ioh, tmc_bctl, sc->sc_busimg);
+ SCSI_LOW_DELAY(10);
}
static void
@@ -224,7 +322,7 @@ stghw_bus_reset(sc)
bus_space_write_1(iot, ioh, tmc_ictl, 0);
bus_space_write_1(iot, ioh, tmc_fctl, 0);
stghw_bcr_write_1(sc, BCTL_RST);
- delay(100000);
+ SCSI_LOW_DELAY(100000);
stghw_bcr_write_1(sc, BCTL_BUSFREE);
}
@@ -233,30 +331,24 @@ stghw_start_selection(sc, cb)
struct stg_softc *sc;
struct slccb *cb;
{
- struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct targ_info *ti = cb->ti;
- struct lun_info *li = ti->ti_li;
register u_int8_t stat;
int s;
- if (li->li_flags & SCSI_LOW_NOPARITY)
- sc->sc_fcRinit &= ~FCTL_PARENB;
- else
- sc->sc_fcRinit |= FCTL_PARENB;
-
+ sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
+ sc->sc_dataout_timeout = 0;
+ sc->sc_ubf_timeout = 0;
stghw_bcr_write_1(sc, BCTL_BUSFREE);
+ bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
s = splhigh();
- if (slp->sl_disc > 0)
+ stat = bus_space_read_1(iot, ioh, tmc_astat);
+ if ((stat & ASTAT_INT) != 0)
{
- stat = bus_space_read_1(iot, ioh, tmc_bstat);
- if (stat & (BSTAT_BSY | BSTAT_SEL | BSTAT_IO))
- {
- splx(s);
- return SCSI_LOW_START_FAIL;
- }
+ splx(s);
+ return SCSI_LOW_START_FAIL;
}
bus_space_write_1(iot, ioh, tmc_scsiid, sc->sc_idbit);
@@ -274,22 +366,18 @@ stg_world_start(sc, fdone)
{
struct scsi_low_softc *slp = &sc->sc_sclow;
int error;
-#ifdef __FreeBSD__
- intrmask_t s;
-#endif
+
+ if ((slp->sl_cfgflags & CFG_NOPARITY) == 0)
+ sc->sc_fcRinit |= FCTL_PARENB;
+ else
+ sc->sc_fcRinit &= ~FCTL_PARENB;
if ((error = stghw_check(sc)) != 0)
return error;
-#ifdef __FreeBSD__
- s = splcam();
-#endif
stghw_init(sc);
scsi_low_bus_reset(slp);
stghw_init(sc);
-#ifdef __FreeBSD__
- splx(s);
-#endif
SOFT_INTR_REQUIRED(slp);
return 0;
@@ -301,11 +389,23 @@ stg_msg(sc, ti, msg)
struct targ_info *ti;
u_int msg;
{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
struct stg_targ_info *sti = (void *) ti;
u_int period, offset;
- if (msg != SCSI_LOW_MSG_SYNCH)
- return EINVAL;
+ if ((msg & SCSI_LOW_MSG_WIDE) != 0)
+ {
+ if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
+ {
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
+ return EINVAL;
+ }
+ return 0;
+ }
+
+ if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
+ return 0;
period = ti->ti_maxsynch.period;
offset = ti->ti_maxsynch.offset;
@@ -324,93 +424,10 @@ stg_msg(sc, ti, msg)
sti->sti_reg_synch ++;
sti->sti_reg_synch |= SSCTL_SYNCHEN | SSCTL_FSYNCHEN;
}
+ bus_space_write_1(iot, ioh, tmc_ssctl, sti->sti_reg_synch);
return 0;
}
-/****************************************************
- * hwfuncs
- ****************************************************/
-static int
-stghw_check(sc)
- struct stg_softc *sc;
-{
- struct scsi_low_softc *slp = &sc->sc_sclow;
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh = sc->sc_ioh;
- u_int16_t lsb, msb;
-
- sc->sc_chip = TMCCHIP_UNK;
- sc->sc_fsz = TMC18C50_FIFOSZ;
- sc->sc_fcb = TMC18C50_FCB;
- sc->sc_fcsp = 0;
-
- sc->sc_fcRinit = FCTL_INTEN;
- sc->sc_fcWinit = FCTL_PARENB | FCTL_INTEN;
-
- if (slp->sl_cfgflags & CFG_NOATTEN)
- sc->sc_imsg = 0;
- else
- sc->sc_imsg = BCTL_ATN;
- sc->sc_busc = BCTL_BUSEN;
-
- lsb = bus_space_read_1(iot, ioh, tmc_idlsb);
- msb = bus_space_read_1(iot, ioh, tmc_idmsb);
- switch (msb << 8 | lsb)
- {
- case 0x6127:
- /* TMCCHIP_1800 not supported. (it's my policy) */
- sc->sc_chip = TMCCHIP_1800;
- return EINVAL;
-
- case 0x60e9:
- sc->sc_chip = TMCCHIP_18C50;
- sc->sc_fcsp |= FCTL_CLRINT;
- if (bus_space_read_1(iot, ioh, tmc_cfg2) & 0x02)
- {
- sc->sc_chip = TMCCHIP_18C30;
- sc->sc_fsz = TMC18C30_FIFOSZ;
- sc->sc_fcb = TMC18C30_FCB;
- }
- break;
-
- default:
- return ENODEV;
- }
-
- sc->sc_icinit = ICTL_ALLINT | sc->sc_fcb;
- return 0;
-}
-
-static void
-stghw_init(sc)
- struct stg_softc *sc;
-{
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh = sc->sc_ioh;
-
- bus_space_write_1(iot, ioh, tmc_ictl, 0);
- stghw_bcr_write_1(sc, BCTL_BUSFREE);
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcsp | sc->sc_fcRinit |
- FCTL_CLRFIFO);
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
- bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
-
- bus_space_write_1(iot, ioh, tmc_ssctl, 0);
-}
-
-static int
-stg_targ_init(sc, ti)
- struct stg_softc *sc;
- struct targ_info *ti;
-{
- struct stg_targ_info *sti = (void *) ti;
-
- ti->ti_maxsynch.period = 0;
- ti->ti_maxsynch.offset = 8;
- sti->sti_reg_synch = 0;
- return 0;
-}
-
/**************************************************************
* General probe attach
**************************************************************/
@@ -456,24 +473,15 @@ stgattachsubr(sc)
printf("\n");
-#ifdef __FreeBSD__
- sc->sc_wc = 0x2000 * 2000; /* XXX need calibration */
-#else
- sc->sc_wc = delaycount * 2000; /* 2 sec */
-#endif
sc->sc_idbit = (1 << slp->sl_hostid);
slp->sl_funcs = &stgfuncs;
+ sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
+ slp->sl_flags |= HW_READ_PADDING;
slp->sl_cfgflags |= CFG_ASYNC; /* XXX */
- if (stghw_check(sc) != 0)
- {
- printf("stg: hardware missing\n");
- return;
- }
-
- (void) scsi_low_attach(slp, 2, STG_NTARGETS, STG_NLUNS,
- sizeof(struct stg_targ_info));
+ (void) scsi_low_attach(slp, 0, STG_NTARGETS, STG_NLUNS,
+ sizeof(struct stg_targ_info), 0);
}
/**************************************************************
@@ -487,10 +495,18 @@ stg_pdma_end(sc, ti)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct slccb *cb = ti->ti_nexus;
+ struct slccb *cb = slp->sl_Qnexus;
u_int len, tres;
slp->sl_flags &= ~HW_PDMASTART;
+ sc->sc_icinit &= ~ICTL_FIFO;
+ sc->sc_dataout_timeout = 0;
+
+ if (cb == NULL)
+ {
+ slp->sl_error |= PDMAERR;
+ goto out;
+ }
if (ti->ti_phase == PH_DATA)
{
@@ -523,6 +539,7 @@ stg_pdma_end(sc, ti)
slp->sl_xname, len);
}
}
+ scsi_low_data_finish(slp);
}
else
{
@@ -531,41 +548,84 @@ stg_pdma_end(sc, ti)
slp->sl_error |= PDMAERR;
}
+out:
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
}
static void
-stg_pio_read(sc, ti)
+stg_pio_read(sc, ti, thold)
struct stg_softc *sc;
struct targ_info *ti;
+ u_int thold;
{
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct sc_p *sp = &slp->sl_scp;
- int tout = sc->sc_wc;
+ int s, tout;
u_int res;
u_int8_t stat;
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_FIFOEN);
+ if ((slp->sl_flags & HW_PDMASTART) == 0)
+ {
+ bus_space_write_1(iot, ioh, tmc_fctl,
+ sc->sc_fcRinit | FCTL_FIFOEN);
+ slp->sl_flags |= HW_PDMASTART;
+ }
- slp->sl_flags |= HW_PDMASTART;
- while (sp->scp_datalen > 0 && tout -- > 0)
+ tout = sc->sc_tmaxcnt;
+ while (tout -- > 0)
{
- res = bus_space_read_2(iot, ioh, tmc_fdcnt);
- if (res == 0)
+ if (thold > 0)
+ {
+ s = splhigh();
+ res = bus_space_read_2(iot, ioh, tmc_fdcnt);
+ if (res < thold)
+ {
+ bus_space_write_1(iot, ioh, tmc_ictl,
+ sc->sc_icinit);
+ splx(s);
+ break;
+ }
+ splx(s);
+ }
+ else
{
stat = bus_space_read_1(iot, ioh, tmc_bstat);
- if ((stat & BSTAT_PHMASK) == BSTAT_IO)
+ res = bus_space_read_2(iot, ioh, tmc_fdcnt);
+ if (res == 0)
+ {
+ if ((stat & PHASE_MASK) != DATA_IN_PHASE)
+ break;
+ if (sp->scp_datalen <= 0)
+ break;
+ SCSI_LOW_DELAY(1);
continue;
- break; /* phase mismatch */
+ }
}
- /* XXX */
+ /* The assumtion res != 0 is valid here */
if (res > sp->scp_datalen)
{
+ if (res == (u_int) -1)
+ break;
+
slp->sl_error |= PDMAERR;
- break;
+ if ((slp->sl_flags & HW_READ_PADDING) == 0)
+ {
+ printf("%s: read padding required\n",
+ slp->sl_xname);
+ break;
+ }
+
+ sp->scp_datalen = 0;
+ if (res > STG_MAX_DATA_SIZE)
+ res = STG_MAX_DATA_SIZE;
+ while (res -- > 0)
+ {
+ (void) bus_space_read_1(iot, ioh, tmc_rfifo);
+ }
+ continue;
}
sp->scp_datalen -= res;
@@ -582,40 +642,74 @@ stg_pio_read(sc, ti)
}
if (tout <= 0)
- printf("%s pio read timeout\n", slp->sl_xname);
+ printf("%s: pio read timeout\n", slp->sl_xname);
}
-#define WFIFO_CRIT 0x100
-
static void
-stg_pio_write(sc, ti)
+stg_pio_write(sc, ti, thold)
struct stg_softc *sc;
struct targ_info *ti;
+ u_int thold;
{
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct sc_p *sp = &slp->sl_scp;
u_int res;
- int tout = sc->sc_wc;
+ int s, tout;
register u_int8_t stat;
- stat = sc->sc_fcWinit | FCTL_FIFOEN | FCTL_FIFOW;
- bus_space_write_1(iot, ioh, tmc_fctl, stat | FCTL_CLRFIFO);
- bus_space_write_1(iot, ioh, tmc_fctl, stat);
+ if ((slp->sl_flags & HW_PDMASTART) == 0)
+ {
+ stat = sc->sc_fcWinit | FCTL_FIFOEN | FCTL_FIFOW;
+ bus_space_write_1(iot, ioh, tmc_fctl, stat | FCTL_CLRFIFO);
+ bus_space_write_1(iot, ioh, tmc_fctl, stat);
+ slp->sl_flags |= HW_PDMASTART;
+ }
- slp->sl_flags |= HW_PDMASTART;
- while (sp->scp_datalen > 0 && tout -- > 0)
+ tout = sc->sc_tmaxcnt;
+ while (tout -- > 0)
{
stat = bus_space_read_1(iot, ioh, tmc_bstat);
- if ((stat & BSTAT_PHMASK) != 0)
+ if ((stat & PHASE_MASK) != DATA_OUT_PHASE)
break;
- if (bus_space_read_2(iot, ioh, tmc_fdcnt) >= WFIFO_CRIT)
- continue;
+ if (sp->scp_datalen <= 0)
+ {
+ if (sc->sc_dataout_timeout == 0)
+ sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ;
+ break;
+ }
+
+ if (thold > 0)
+ {
+ s = splhigh();
+ res = bus_space_read_2(iot, ioh, tmc_fdcnt);
+ if (res > thold)
+ {
+ bus_space_write_1(iot, ioh, tmc_ictl,
+ sc->sc_icinit);
+ splx(s);
+ break;
+ }
+ splx(s);
+ }
+ else
+ {
+ res = bus_space_read_2(iot, ioh, tmc_fdcnt);
+ if (res > sc->sc_maxwsize / 2)
+ {
+ SCSI_LOW_DELAY(1);
+ continue;
+ }
+ }
+
+ if (res == (u_int) -1)
+ break;
+ res = sc->sc_maxwsize - res;
+ if (res > sp->scp_datalen)
+ res = sp->scp_datalen;
- res = (sp->scp_datalen > WFIFO_CRIT) ?
- WFIFO_CRIT : sp->scp_datalen;
sp->scp_datalen -= res;
if ((res & 0x1) != 0)
{
@@ -630,7 +724,7 @@ stg_pio_write(sc, ti)
}
if (tout <= 0)
- printf("%s pio write timeout\n", slp->sl_xname);
+ printf("%s: pio write timeout\n", slp->sl_xname);
}
static int
@@ -642,23 +736,22 @@ stg_negate_signal(sc, mask, s)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
- int wc = (sc->sc_wc >> 2);
+ int wc;
u_int8_t regv;
- do
+ for (wc = 0; wc < STG_DELAY_MAX / STG_DELAY_INTERVAL; wc ++)
{
regv = bus_space_read_1(bst, bsh, tmc_bstat);
- if (regv == 0xff)
- return EIO;
- }
- while ((regv & mask) != 0 && (-- wc) > 0);
+ if (regv == (u_int8_t) -1)
+ return -1;
+ if ((regv & mask) == 0)
+ return 1;
- if (wc <= 0)
- {
- printf("%s: %s singal off timeout \n", slp->sl_xname, s);
- return EIO;
+ SCSI_LOW_DELAY(STG_DELAY_INTERVAL);
}
- return 0;
+
+ printf("%s: %s stg_negate_signal timeout\n", slp->sl_xname, s);
+ return -1;
}
static int
@@ -669,49 +762,39 @@ stg_expect_signal(sc, phase, mask)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
- int wc = (sc->sc_wc >> 2);
- int rv = -1;
+ int wc;
u_int8_t ph;
- phase &= BSTAT_PHMASK;
- do
+ phase &= PHASE_MASK;
+ for (wc = 0; wc < STG_DELAY_MAX / STG_DELAY_INTERVAL; wc ++)
{
ph = bus_space_read_1(bst, bsh, tmc_bstat);
- if (ph == 0xff) {
- rv = -1;
- break;
- }
- if ((ph & BSTAT_PHMASK) != phase) {
- rv = 0;
- break;
- }
- if ((ph & mask) != 0) {
- rv = 1;
- break;
- }
- }
- while (wc -- > 0);
+ if (ph == (u_int8_t) -1)
+ return -1;
+ if ((ph & PHASE_MASK) != phase)
+ return 0;
+ if ((ph & mask) != 0)
+ return 1;
- if (wc <= 0) {
- printf("%s: stg_expect_signal timeout\n", slp->sl_xname);
- rv = -1;
+ SCSI_LOW_DELAY(STG_DELAY_INTERVAL);
}
- return rv;
+
+ printf("%s: stg_expect_signal timeout\n", slp->sl_xname);
+ return -1;
}
static int
-stg_xfer(sc, buf, len, phase)
+stg_xfer(sc, buf, len, phase, clear_atn)
struct stg_softc *sc;
u_int8_t *buf;
int len;
int phase;
+ int clear_atn;
{
- struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- int rv, ptr, atn;
+ int rv, ptr;
- atn = (scsi_low_is_msgout_continue(slp->sl_nexus) != 0);
if (phase & BSTAT_IO)
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
else
@@ -723,10 +806,11 @@ stg_xfer(sc, buf, len, phase)
if (rv <= 0)
goto bad;
- if (len == 1 && atn == 0)
+ if (len == 1 && clear_atn != 0)
{
sc->sc_busc &= ~BCTL_ATN;
stghw_bcr_write_1(sc, sc->sc_busc);
+ SCSI_LOW_DEASSERT_ATN(&sc->sc_sclow);
}
if (phase & BSTAT_IO)
@@ -737,6 +821,7 @@ stg_xfer(sc, buf, len, phase)
{
bus_space_write_1(iot, ioh, tmc_wdata, buf[ptr ++]);
}
+
stg_negate_signal(sc, BSTAT_ACK, "xfer<ACK>");
}
@@ -755,44 +840,83 @@ stg_reselected(sc)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct targ_info *ti;
+ int tout;
u_int sid;
+ u_int8_t regv;
if (slp->sl_selid != NULL)
{
/* XXX:
* Selection vs Reselection conflicts.
*/
-#ifdef STG_STATICS
- stg_statics[slp->sl_selid->ti_id].sprious_arbit_fail_0 ++;
-#endif /* STG_STATICS */
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
stghw_bcr_write_1(sc, BCTL_BUSFREE);
}
+ else if (slp->sl_Tnexus != NULL)
+ {
+ printf("%s: unexpected termination\n", slp->sl_xname);
+ stg_disconnected(sc, slp->sl_Tnexus);
+ }
/* XXX:
* We should ack the reselection as soon as possible,
* becuase the target would abort the current reselection seq
* due to reselection timeout.
*/
+ tout = STG_DELAY_SELECT_POLLING_MAX;
+ while (tout -- > 0)
+ {
+ regv = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((regv & (BSTAT_IO | BSTAT_SEL | BSTAT_BSY)) ==
+ (BSTAT_IO | BSTAT_SEL))
+ {
+ SCSI_LOW_DELAY(1);
+ regv = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((regv & (BSTAT_IO | BSTAT_SEL | BSTAT_BSY)) ==
+ (BSTAT_IO | BSTAT_SEL))
+ goto reselect_start;
+ }
+ SCSI_LOW_DELAY(1);
+ }
+ printf("%s: reselction timeout I\n", slp->sl_xname);
+ return EJUSTRETURN;
+
+reselect_start:
sid = (u_int) bus_space_read_1(iot, ioh, tmc_scsiid);
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcsp |
- sc->sc_fcRinit | FCTL_CLRFIFO);
+ if ((sid & sc->sc_idbit) == 0)
+ {
+ /* not us */
+ return EJUSTRETURN;
+ }
+
+ bus_space_write_1(iot, ioh, tmc_fctl,
+ sc->sc_fcRinit | FCTL_CLRFIFO | FCTL_CLRINT);
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
stghw_bcr_write_1(sc, sc->sc_busc | BCTL_BSY);
+ while (tout -- > 0)
+ {
+ regv = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((regv & (BSTAT_SEL | BSTAT_BSY)) == BSTAT_BSY)
+ goto reselected;
+ SCSI_LOW_DELAY(1);
+ }
+ printf("%s: reselction timeout II\n", slp->sl_xname);
+ return EJUSTRETURN;
+
+reselected:
sid &= ~sc->sc_idbit;
sid = ffs(sid) - 1;
- if ((ti = scsi_low_reselected(slp, sid)) == NULL)
+ if (scsi_low_reselected(slp, sid) == NULL)
return EJUSTRETURN;
#ifdef STG_STATICS
- stg_statics[sid].reselect ++;
+ stg_statics.reselect ++;
#endif /* STG_STATICS */
return EJUSTRETURN;
}
-static __inline int
+static int
stg_disconnected(sc, ti)
struct stg_softc *sc;
struct targ_info *ti;
@@ -805,12 +929,13 @@ stg_disconnected(sc, ti)
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO);
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
stghw_bcr_write_1(sc, BCTL_BUSFREE);
- sc->sc_fcRinit &= ~FCTL_PARENB;
+ sc->sc_icinit &= ~ICTL_FIFO;
sc->sc_busc &= ~BCTL_ATN;
+ sc->sc_dataout_timeout = 0;
+ sc->sc_ubf_timeout = 0;
#ifdef STG_STATICS
- if (slp->sl_msgphase == MSGPH_DISC)
- stg_statics[ti->ti_id].disconnect ++;
+ stg_statics.disconnect ++;
#endif /* STG_STATICS */
scsi_low_disconnected(slp, ti);
return 1;
@@ -820,51 +945,81 @@ stg_disconnected(sc, ti)
* SEQUENCER
**************************************************************/
static int
-stg_nexus(sc, ti)
+stg_target_nexus_establish(sc)
struct stg_softc *sc;
- struct targ_info *ti;
{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct lun_info *li = ti->ti_li;
+ struct targ_info *ti = slp->sl_Tnexus;
struct stg_targ_info *sti = (void *) ti;
- if (li->li_flags & SCSI_LOW_NOPARITY)
- sc->sc_fcRinit &= ~FCTL_PARENB;
- else
- sc->sc_fcRinit |= FCTL_PARENB;
-
bus_space_write_1(iot, ioh, tmc_ssctl, sti->sti_reg_synch);
+ if ((stg_io_control & STG_FIFO_INTERRUPTS) != 0)
+ {
+ sc->sc_icinit |= ICTL_FIFO;
+ }
return 0;
}
static int
-stghw_select_targ_wait(sc, id)
+stg_lun_nexus_establish(sc)
struct stg_softc *sc;
- int id;
+{
+
+ return 0;
+}
+
+static int
+stg_ccb_nexus_establish(sc)
+ struct stg_softc *sc;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ struct slccb *cb = slp->sl_Qnexus;
+
+ sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
+ return 0;
+}
+
+#define STGHW_SELECT_INTERVAL 10
+
+static int
+stghw_select_targ_wait(sc, mu)
+ struct stg_softc *sc;
+ int mu;
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- int wc, error = EIO;
- bus_space_write_1(iot, ioh, tmc_scsiid, sc->sc_idbit | (1 << id));
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit & (~FCTL_INTEN));
- stghw_bcr_write_1(sc, sc->sc_busc | sc->sc_imsg | BCTL_SEL);
-
- for (wc = 50000; wc; wc--)
+ mu = mu / STGHW_SELECT_INTERVAL;
+ while (mu -- > 0)
{
- if (bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY)
+ if ((bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) == 0)
{
- error = 0;
- break;
+ SCSI_LOW_DELAY(STGHW_SELECT_INTERVAL);
+ continue;
+ }
+ SCSI_LOW_DELAY(1);
+ if ((bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) != 0)
+ {
+ return 0;
}
-
- delay(1);
}
+ return ENXIO;
+}
+
+static void
+stg_selection_done_and_expect_msgout(sc)
+ struct stg_softc *sc;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO);
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
- return error;
+ stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc);
+ SCSI_LOW_ASSERT_ATN(slp);
}
int
@@ -878,7 +1033,8 @@ stgintr(arg)
struct targ_info *ti;
struct physio_proc *pp;
struct buf *bp;
- int len;
+ u_int derror, flags;
+ int len, s;
u_int8_t status, astatus, regv;
/*******************************************
@@ -890,14 +1046,16 @@ stgintr(arg)
astatus = bus_space_read_1(iot, ioh, tmc_astat);
status = bus_space_read_1(iot, ioh, tmc_bstat);
- if ((astatus & ASTAT_STATMASK) == 0)
+ if ((astatus & ASTAT_STATMASK) == 0 || astatus == (u_int8_t) -1)
return 0;
+ bus_space_write_1(iot, ioh, tmc_ictl, 0);
if (astatus & ASTAT_SCSIRST)
{
bus_space_write_1(iot, ioh, tmc_fctl,
sc->sc_fcRinit | FCTL_CLRFIFO);
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
+ bus_space_write_1(iot, ioh, tmc_ictl, 0);
scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT,
"bus reset (power off?)");
@@ -911,10 +1069,12 @@ stgintr(arg)
if (stg_debug)
{
scsi_low_print(slp, NULL);
- printf("%s st %x ist %x\n\n", slp->sl_xname,
+ printf("%s: st %x ist %x\n\n", slp->sl_xname,
status, astatus);
+#ifdef DDB
if (stg_debug > 1)
- Debugger();
+ SCSI_LOW_DEBUGGER("stg");
+#endif /* DDB */
}
#endif /* STG_DEBUG */
@@ -924,34 +1084,20 @@ stgintr(arg)
if ((status & RESEL_PHASE_MASK)== PHASE_RESELECTED)
{
if (stg_reselected(sc) == EJUSTRETURN)
- return 1;
+ goto out;
}
- if ((ti = slp->sl_nexus) == NULL)
- {
- status = bus_space_read_1(iot, ioh, tmc_bstat);
- if ((status & PHASE_MASK) != MESSAGE_IN_PHASE)
- return 1;
-
- /* XXX:
- * Some scsi devices overrun scsi phase.
- */
- if (stg_reselected(sc) == EJUSTRETURN)
- {
-#ifdef STG_STATICS
- if ((ti = slp->sl_nexus) != NULL)
- stg_statics[ti->ti_id].sprious_arbit_fail_1 ++;
-#endif /* STG_STATICS */
- return 1;
- }
- }
+ if ((ti = slp->sl_Tnexus) == NULL)
+ return 0;
+ derror = 0;
if ((astatus & ASTAT_PARERR) != 0 && ti->ti_phase != PH_ARBSTART &&
(sc->sc_fcRinit & FCTL_PARENB) != 0)
{
slp->sl_error |= PARITYERR;
- if (ti->ti_phase == PH_MSGIN)
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 1);
+ derror = SCSI_LOW_DATA_PE;
+ if ((status & PHASE_MASK) == MESSAGE_IN_PHASE)
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
else
scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1);
}
@@ -963,7 +1109,12 @@ stgintr(arg)
{
case PH_ARBSTART:
if ((astatus & ASTAT_ARBIT) == 0)
+ {
+#ifdef STG_STATICS
+ stg_statics.arbit_fail_0 ++;
+#endif /* STG_STATICS */
goto arb_fail;
+ }
status = bus_space_read_1(iot, ioh, tmc_bstat);
if ((status & BSTAT_IO) != 0)
@@ -972,167 +1123,311 @@ stgintr(arg)
* Selection vs Reselection conflicts.
*/
#ifdef STG_STATICS
- stg_statics[ti->ti_id].sprious_arbit_fail_2 ++;
+ stg_statics.arbit_fail_1 ++;
#endif /* STG_STATICS */
arb_fail:
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
stghw_bcr_write_1(sc, BCTL_BUSFREE);
- SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
- scsi_low_clear_nexus(slp, ti);
- return 1;
+ scsi_low_arbit_fail(slp, slp->sl_Qnexus);
+ goto out;
}
/*
* selection assert start.
*/
SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
- scsi_low_arbit_win(slp, ti);
-#ifdef STG_ALT_SELECTION
+ scsi_low_arbit_win(slp);
+
+ s = splhigh();
bus_space_write_1(iot, ioh, tmc_scsiid,
sc->sc_idbit | (1 << ti->ti_id));
- /* assert busy */
- stghw_bcr_write_1(sc, sc->sc_imsg | BCTL_BSY | sc->sc_busc);
- /* arb flag clear */
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit);
- /* assert sel */
- stghw_bcr_write_1(sc, sc->sc_imsg | BCTL_BSY | sc->sc_busc | BCTL_SEL);
- delay(3);
- /* deassert busy */
stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc | BCTL_SEL);
-#else /* !STG_ALT_SELECTION */
- bus_space_write_1(iot, ioh, tmc_scsiid,
- sc->sc_idbit | (1 << ti->ti_id));
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit);
- stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc | BCTL_SEL);
-#endif /* !STG_ALT_SELECTION */
- return 1;
+ if ((stg_io_control & STG_WAIT_FOR_SELECT) != 0)
+ {
+ /* selection abort delay 200 + 100 micro sec */
+ if (stghw_select_targ_wait(sc, 300) == 0)
+ {
+ SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
+ stg_selection_done_and_expect_msgout(sc);
+ }
+ }
+ splx(s);
+ goto out;
case PH_SELSTART:
if ((status & BSTAT_BSY) == 0)
{
- if (stghw_select_targ_wait(sc, ti->ti_id) != 0)
+ /* selection timeout delay 250 ms */
+ if (stghw_select_targ_wait(sc, 250 * 1000) != 0)
{
- return stg_disconnected(sc, ti);
+ stg_disconnected(sc, ti);
+ goto out;
}
}
- /*
- * attention assert.
- */
SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit |
- FCTL_CLRFIFO);
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
- stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc);
- SCSI_LOW_TARGET_ASSERT_ATN(ti);
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
- return 1;
+ stg_selection_done_and_expect_msgout(sc);
+ goto out;
+
+ case PH_SELECTED:
+ if ((status & BSTAT_REQ) == 0)
+ goto out;
+ stg_target_nexus_establish(sc);
+ break;
case PH_RESEL:
+ if ((status & BSTAT_REQ) == 0)
+ goto out;
+
/* clear a busy line */
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
stghw_bcr_write_1(sc, sc->sc_busc);
+ stg_target_nexus_establish(sc);
if ((status & PHASE_MASK) != MESSAGE_IN_PHASE)
{
+ printf("%s: unexpected phase after reselect\n",
+ slp->sl_xname);
+ slp->sl_error |= FATALIO;
scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
- return 1;
+ goto out;
}
break;
}
/*******************************************
- * scsi seq
+ * data phase
*******************************************/
- if (slp->sl_flags & HW_PDMASTART)
+ if ((slp->sl_flags & HW_PDMASTART) && STG_IS_PHASE_DATA(status) == 0)
+ {
+ if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
+ stg_pio_read(sc, ti, 0);
+
stg_pdma_end(sc, ti);
+ }
+ /*******************************************
+ * scsi seq
+ *******************************************/
switch (status & PHASE_MASK)
{
case COMMAND_PHASE:
+ if (stg_expect_signal(sc, COMMAND_PHASE, BSTAT_REQ) <= 0)
+ break;
+
SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
if (scsi_low_cmd(slp, ti) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
- if (stg_xfer(sc, slp->sl_scp.scp_cmd,
- slp->sl_scp.scp_cmdlen, COMMAND_PHASE) != 0)
+ if (stg_xfer(sc, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen,
+ COMMAND_PHASE, 0) != 0)
{
- printf("%s: MSGOUT short\n", slp->sl_xname);
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_RESET, 0);
+ printf("%s: CMDOUT short\n", slp->sl_xname);
}
break;
case DATA_OUT_PHASE:
SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
pp = physio_proc_enter(bp);
- stg_pio_write(sc, ti);
+ if ((sc->sc_icinit & ICTL_FIFO) != 0)
+ stg_pio_write(sc, ti, sc->sc_wthold);
+ else
+ stg_pio_write(sc, ti, 0);
physio_proc_leave(pp);
break;
case DATA_IN_PHASE:
SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
pp = physio_proc_enter(bp);
- stg_pio_read(sc, ti);
+ if ((sc->sc_icinit & ICTL_FIFO) != 0)
+ stg_pio_read(sc, ti, sc->sc_rthold);
+ else
+ stg_pio_read(sc, ti, 0);
physio_proc_leave(pp);
break;
case STATUS_PHASE:
+ regv = stg_expect_signal(sc, STATUS_PHASE, BSTAT_REQ);
+ if (regv <= 0)
+ break;
+
SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
- ti->ti_status = bus_space_read_1(iot, ioh, tmc_rdata);
+ regv = bus_space_read_1(iot, ioh, tmc_sdna);
+ if (scsi_low_statusin(slp, ti, regv | derror) != 0)
+ {
+ scsi_low_attention(slp);
+ }
+ if (regv != bus_space_read_1(iot, ioh, tmc_rdata))
+ {
+ printf("%s: STATIN: data mismatch\n", slp->sl_xname);
+ }
+ stg_negate_signal(sc, BSTAT_ACK, "statin<ACK>");
break;
case MESSAGE_OUT_PHASE:
+ if (stg_expect_signal(sc, MESSAGE_OUT_PHASE, BSTAT_REQ) <= 0)
+ break;
+
SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
- len = scsi_low_msgout(slp, ti);
- if (stg_xfer(sc, ti->ti_msgoutstr, len, MESSAGE_OUT_PHASE))
+ flags = (ti->ti_ophase != ti->ti_phase) ?
+ SCSI_LOW_MSGOUT_INIT : 0;
+ len = scsi_low_msgout(slp, ti, flags);
+
+ if (len > 1 && slp->sl_atten == 0)
+ {
+ scsi_low_attention(slp);
+ }
+
+ if (stg_xfer(sc, ti->ti_msgoutstr, len, MESSAGE_OUT_PHASE,
+ slp->sl_clear_atten) != 0)
{
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_RESET, 0);
printf("%s: MSGOUT short\n", slp->sl_xname);
}
+ else
+ {
+ if (slp->sl_msgphase >= MSGPH_ABORT)
+ {
+ stg_disconnected(sc, ti);
+ }
+ }
break;
case MESSAGE_IN_PHASE:
+ /* confirm phase and req signal */
+ if (stg_expect_signal(sc, MESSAGE_IN_PHASE, BSTAT_REQ) <= 0)
+ break;
+
SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
- /* confirm REQ signal */
- regv = stg_expect_signal(sc, MESSAGE_IN_PHASE, BSTAT_REQ);
- if (regv <= 0)
- {
- printf("%s: MSGIN: no req\n", slp->sl_xname);
- break;
- }
/* read data with NOACK */
- regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, tmc_sdna);
+ regv = bus_space_read_1(iot, ioh, tmc_sdna);
- scsi_low_msgin(slp, ti, regv);
+ if (scsi_low_msgin(slp, ti, derror | regv) == 0)
+ {
+ if (scsi_low_is_msgout_continue(ti, 0) != 0)
+ {
+ scsi_low_attention(slp);
+ }
+ }
/* read data with ACK */
- if (regv != bus_space_read_1(sc->sc_iot, sc->sc_ioh, tmc_rdata))
+ if (regv != bus_space_read_1(iot, ioh, tmc_rdata))
{
printf("%s: MSGIN: data mismatch\n", slp->sl_xname);
}
- if (slp->sl_msgphase != 0)
+ /* wait for the ack negated */
+ stg_negate_signal(sc, BSTAT_ACK, "msgin<ACK>");
+
+ if (slp->sl_msgphase != 0 && slp->sl_msgphase < MSGPH_ABORT)
{
- stg_negate_signal(sc, BSTAT_ACK, "discon<ACK>");
- return stg_disconnected(sc, ti);
+ stg_disconnected(sc, ti);
}
break;
case BUSFREE_PHASE:
- printf("%s unexpected disconnection\n", slp->sl_xname);
- return stg_disconnected(sc, ti);
+ printf("%s: unexpected disconnect\n", slp->sl_xname);
+ stg_disconnected(sc, ti);
+ break;
default:
- printf("%s unknown phase bus %x intr %x\n",
+ slp->sl_error |= FATALIO;
+ printf("%s: unknown phase bus %x intr %x\n",
slp->sl_xname, status, astatus);
break;
}
+out:
+ bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
return 1;
}
+
+static int
+stg_timeout(sc)
+ struct stg_softc *sc;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int tout, count;
+ u_int8_t status;
+
+ if (slp->sl_Tnexus == NULL)
+ return 0;
+
+ status = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((status & PHASE_MASK) == 0)
+ {
+ if (sc->sc_ubf_timeout ++ == 0)
+ return 0;
+
+ printf("%s: unexpected bus free detected\n", slp->sl_xname);
+ slp->sl_error |= FATALIO;
+ scsi_low_print(slp, slp->sl_Tnexus);
+ stg_disconnected(sc, slp->sl_Tnexus);
+ return 0;
+ }
+
+ switch (status & PHASE_MASK)
+ {
+ case DATA_OUT_PHASE:
+ if (sc->sc_dataout_timeout == 0)
+ break;
+ if ((status & BSTAT_REQ) == 0)
+ break;
+ if (bus_space_read_2(iot, ioh, tmc_fdcnt) != 0)
+ break;
+ if ((-- sc->sc_dataout_timeout) > 0)
+ break;
+
+ slp->sl_error |= PDMAERR;
+ if ((slp->sl_flags & HW_WRITE_PADDING) == 0)
+ {
+ printf("%s: write padding required\n",
+ slp->sl_xname);
+ break;
+ }
+
+ bus_space_write_1(iot, ioh, tmc_ictl, 0);
+
+ tout = STG_DELAY_MAX;
+ while (tout --)
+ {
+ status = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((status & PHASE_MASK) != DATA_OUT_PHASE)
+ break;
+
+ if (bus_space_read_2(iot, ioh, tmc_fdcnt) != 0)
+ {
+ SCSI_LOW_DELAY(1);
+ continue;
+ }
+
+ for (count = sc->sc_maxwsize; count > 0; count --)
+ bus_space_write_1(iot, ioh, tmc_wfifo, 0);
+ }
+
+ status = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((status & PHASE_MASK) == DATA_OUT_PHASE)
+ sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ;
+
+ bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
diff --git a/sys/dev/stg/tmc18c30_isa.c b/sys/dev/stg/tmc18c30_isa.c
index 53df893..21e9361 100644
--- a/sys/dev/stg/tmc18c30_isa.c
+++ b/sys/dev/stg/tmc18c30_isa.c
@@ -237,10 +237,13 @@ static void
stg_isa_unload(device_t devi)
{
struct stg_softc *sc = device_get_softc(devi);
+ intrmask_t s;
printf("%s: unload\n",sc->sc_sclow.sl_xname);
+ s = splcam();
scsi_low_deactivate((struct scsi_low_softc *)sc);
scsi_low_dettach(&sc->sc_sclow);
+ splx(s);
}
static int
@@ -263,7 +266,7 @@ stgattach(device_t devi)
struct scsi_low_softc *slp;
u_int32_t flags = device_get_flags(devi);
u_int iobase = bus_get_resource_start(devi, SYS_RES_IOPORT, 0);
-
+ intrmask_t s;
char dvname[16];
strcpy(dvname,"stg");
@@ -288,9 +291,9 @@ stgattach(device_t devi)
slp->sl_hostid = STG_HOSTID;
slp->sl_cfgflags = flags;
+ s = splcam();
stgattachsubr(sc);
-
- sc->sc_ih = stgintr;
+ splx(s);
return(STGIOSZ);
}
diff --git a/sys/dev/stg/tmc18c30_pccard.c b/sys/dev/stg/tmc18c30_pccard.c
index c1bf0e9..0cf518f 100644
--- a/sys/dev/stg/tmc18c30_pccard.c
+++ b/sys/dev/stg/tmc18c30_pccard.c
@@ -319,10 +319,13 @@ static void
stg_card_unload(DEVPORT_PDEVICE devi)
{
struct stg_softc *sc = DEVPORT_PDEVGET_SOFTC(devi);
+ intrmask_t s;
printf("%s: unload\n",sc->sc_sclow.sl_xname);
+ s = splcam();
scsi_low_deactivate((struct scsi_low_softc *)sc);
scsi_low_dettach(&sc->sc_sclow);
+ splx(s);
}
static int
@@ -353,7 +356,7 @@ stgattach(DEVPORT_PDEVICE devi)
struct scsi_low_softc *slp;
u_int32_t flags = DEVPORT_PDEVFLAGS(devi);
u_int iobase = DEVPORT_PDEVIOBASE(devi);
-
+ intrmask_t s;
char dvname[16];
strcpy(dvname,"stg");
@@ -393,9 +396,9 @@ stgattach(DEVPORT_PDEVICE devi)
slp->sl_hostid = STG_HOSTID;
slp->sl_cfgflags = flags;
+ s = splcam();
stgattachsubr(sc);
-
- sc->sc_ih = stgintr;
+ splx(s);
return(STGIOSZ);
}
diff --git a/sys/dev/stg/tmc18c30reg.h b/sys/dev/stg/tmc18c30reg.h
index 4a29f60..9c84d89 100644
--- a/sys/dev/stg/tmc18c30reg.h
+++ b/sys/dev/stg/tmc18c30reg.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $NecBSD: tmc18c30reg.h,v 1.4 1998/03/14 07:05:23 kmatsuda Exp $ */
+/* $NecBSD: tmc18c30reg.h,v 1.4.24.1 2001/06/08 06:27:50 honda Exp $ */
/* $NetBSD$ */
/*
@@ -57,14 +57,13 @@
#define BSTAT_REQ 0x10
#define BSTAT_SEL 0x20
#define BSTAT_ACK 0x40
-#define BSTAT_PHMASK (BSTAT_MSG | BSTAT_IO | BSTAT_CMD)
#define tmc_ictl 0x02
#define ICTL_FIFO 0x10
#define ICTL_ARBIT 0x20
#define ICTL_SEL 0x40
#define ICTL_CD 0x80
-#define ICTL_ALLINT (ICTL_ARBIT | ICTL_CD | ICTL_SEL)
+#define ICTL_ALLINT (ICTL_ARBIT | ICTL_CD | ICTL_SEL | ICTL_FIFO)
#define tmc_astat 0x02
#define ASTAT_INT 0x01
#define ASTAT_ARBIT 0x02
@@ -112,6 +111,7 @@
#define tmc_cfg1 0x0a
#define tmc_ioctl 0x0b
+#define IOCTL_IO32 0x80
#define tmc_cfg2 0x0b
#define tmc_wfifo 0x0c
@@ -127,11 +127,14 @@
#define STATUS_PHASE (BSTAT_CMD|BSTAT_BSY|BSTAT_IO)
#define MESSAGE_OUT_PHASE (BSTAT_CMD|BSTAT_MSG|BSTAT_BSY)
#define MESSAGE_IN_PHASE (BSTAT_CMD|BSTAT_MSG|BSTAT_BSY|BSTAT_IO)
-
#define PHASE_RESELECTED (BSTAT_SEL|BSTAT_IO)
-#define PHASE_MASK 0x2f
-#define RESEL_PHASE_MASK 0x2e
+#define BSTAT_PHMASK (BSTAT_MSG | BSTAT_IO | BSTAT_CMD)
+#define PHASE_MASK (BSTAT_SEL | BSTAT_BSY | BSTAT_PHMASK)
+#define RESEL_PHASE_MASK (BSTAT_SEL | BSTAT_PHMASK)
+
+#define STG_IS_PHASE_DATA(st) \
+ ((((st) & PHASE_MASK) & ~BSTAT_IO) == BSTAT_BSY)
/* chip type */
#define TMCCHIP_UNK 0x00
diff --git a/sys/dev/stg/tmc18c30var.h b/sys/dev/stg/tmc18c30var.h
index 0940fc7..ea713a0 100644
--- a/sys/dev/stg/tmc18c30var.h
+++ b/sys/dev/stg/tmc18c30var.h
@@ -1,12 +1,12 @@
/* $FreeBSD$ */
-/* $NecBSD: tmc18c30var.h,v 1.12 1998/11/30 00:08:30 honda Exp $ */
+/* $NecBSD: tmc18c30var.h,v 1.12.18.2 2001/06/13 05:51:23 honda Exp $ */
/* $NetBSD$ */
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1996, 1997, 1998
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
- * Copyright (c) 1996, 1997, 1998
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001
* Naofumi HONDA. All rights reserved.
* Copyright (c) 1996, 1997, 1998
* Kouichi Matsuda. All rights reserved.
@@ -44,45 +44,57 @@
struct stg_softc {
struct scsi_low_softc sc_sclow; /* generic data */
+#ifdef __NetBSD__
bus_space_tag_t sc_iot;
bus_space_tag_t sc_memt;
bus_space_handle_t sc_ioh;
void *sc_ih;
+#endif /* __NetBSD__ */
- int sc_wc; /* weight counter */
+#ifdef __FreeBSD__
+ bus_space_tag_t sc_iot;
+ bus_space_tag_t sc_memt;
+ bus_space_handle_t sc_ioh;
+#if __FreeBSD_version >= 400001
+ int port_rid;
+ int irq_rid;
+ int mem_rid;
+ struct resource *port_res;
+ struct resource *irq_res;
+ struct resource *mem_res;
+
+ void *stg_intrhand;
+#endif /* __FreeBSD_version */
+#endif /* __FreeBSD__ */
+
+ int sc_tmaxcnt;
u_int sc_chip; /* chip type */
u_int sc_fsz; /* fifo size */
u_int sc_idbit; /* host id bit */
- u_int8_t sc_fcb; /* fifo intr thread */
+ u_int sc_wthold; /* write thread */
+ u_int sc_rthold; /* read thread */
+ u_int sc_maxwsize; /* max write size */
+ int sc_dataout_timeout; /* data out timeout counter */
+ int sc_ubf_timeout; /* unexpected bus free timeout */
u_int8_t sc_fcWinit; /* write flags */
u_int8_t sc_fcRinit; /* read flags */
- u_int8_t sc_fcsp; /* special control flags */
u_int8_t sc_icinit; /* interrupt masks */
u_int8_t sc_busc; /* default bus control register */
u_int8_t sc_imsg; /* identify msg required */
u_int8_t sc_busimg; /* bus control register image */
-#if defined (__FreeBSD__) && __FreeBSD_version >= 400001
- int port_rid;
- int irq_rid;
- int mem_rid;
- struct resource *port_res;
- struct resource *irq_res;
- struct resource *mem_res;
- void *stg_intrhand;
-#endif
};
/*****************************************************************
- * Target information
+ * Lun information
*****************************************************************/
struct stg_targ_info {
- struct targ_info sti_ti; /* generic data */
+ struct targ_info sti_ti; /* generic data */
- u_int8_t sti_reg_synch; /* synch register per target */
+ u_int8_t sti_reg_synch; /* synch register per lun */
};
/*****************************************************************
OpenPOWER on IntegriCloud