diff options
author | non <non@FreeBSD.org> | 2001-07-14 00:38:51 +0000 |
---|---|---|
committer | non <non@FreeBSD.org> | 2001-07-14 00:38:51 +0000 |
commit | e91272502526170cc4f62c2357a8b7d3ee9b2c27 (patch) | |
tree | 01f4c48045db66f0e363a543a36a88e13470d6c9 /sys | |
parent | a67c5263965b3cce0db11089854bd6f3f56f2f8e (diff) | |
download | FreeBSD-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.c | 4992 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_low.h | 678 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_low_pisa.c | 129 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_low_pisa.h | 21 | ||||
-rw-r--r-- | sys/conf/options.pc98 | 4 | ||||
-rw-r--r-- | sys/dev/ct/bshw_machdep.c | 396 | ||||
-rw-r--r-- | sys/dev/ct/bshwvar.h | 32 | ||||
-rw-r--r-- | sys/dev/ct/ct.c | 809 | ||||
-rw-r--r-- | sys/dev/ct/ct_isa.c | 114 | ||||
-rw-r--r-- | sys/dev/ct/ct_machdep.h | 149 | ||||
-rw-r--r-- | sys/dev/ct/ctvar.h | 70 | ||||
-rw-r--r-- | sys/dev/ncv/ncr53c500.c | 673 | ||||
-rw-r--r-- | sys/dev/ncv/ncr53c500_pccard.c | 8 | ||||
-rw-r--r-- | sys/dev/ncv/ncr53c500hw.h | 22 | ||||
-rw-r--r-- | sys/dev/ncv/ncr53c500hwtab.h | 20 | ||||
-rw-r--r-- | sys/dev/ncv/ncr53c500reg.h | 7 | ||||
-rw-r--r-- | sys/dev/ncv/ncr53c500var.h | 40 | ||||
-rw-r--r-- | sys/dev/nsp/nsp.c | 1326 | ||||
-rw-r--r-- | sys/dev/nsp/nsp_pccard.c | 8 | ||||
-rw-r--r-- | sys/dev/nsp/nspreg.h | 22 | ||||
-rw-r--r-- | sys/dev/nsp/nspvar.h | 54 | ||||
-rw-r--r-- | sys/dev/stg/tmc18c30.c | 995 | ||||
-rw-r--r-- | sys/dev/stg/tmc18c30_isa.c | 9 | ||||
-rw-r--r-- | sys/dev/stg/tmc18c30_pccard.c | 9 | ||||
-rw-r--r-- | sys/dev/stg/tmc18c30reg.h | 15 | ||||
-rw-r--r-- | sys/dev/stg/tmc18c30var.h | 48 |
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, ®v, 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, ®v, 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, ®v, 1, SCSI_LOW_READ); - scsi_low_msgin(slp, ti, regv); + + ct_xfer(ct, ®v, 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 */ }; /***************************************************************** |