summaryrefslogtreecommitdiffstats
path: root/usr.sbin/ncrcontrol
diff options
context:
space:
mode:
authorse <se@FreeBSD.org>1994-10-12 12:02:52 +0000
committerse <se@FreeBSD.org>1994-10-12 12:02:52 +0000
commit1ce59152137cebda41511acadbda3d02a73dc3fb (patch)
tree27cda998b2b6f27a9424246832b26c0d4662d02f /usr.sbin/ncrcontrol
downloadFreeBSD-src-1ce59152137cebda41511acadbda3d02a73dc3fb.zip
FreeBSD-src-1ce59152137cebda41511acadbda3d02a73dc3fb.tar.gz
Submitted by: Wolfgang Stanglmeier <wolf@dentaro.GUN.de>
Config and statuts display utility for the NCR PCI SCSI driver.
Diffstat (limited to 'usr.sbin/ncrcontrol')
-rw-r--r--usr.sbin/ncrcontrol/Makefile8
-rw-r--r--usr.sbin/ncrcontrol/ncrcontrol.1286
-rw-r--r--usr.sbin/ncrcontrol/ncrcontrol.c1630
3 files changed, 1924 insertions, 0 deletions
diff --git a/usr.sbin/ncrcontrol/Makefile b/usr.sbin/ncrcontrol/Makefile
new file mode 100644
index 0000000..86c39ee
--- /dev/null
+++ b/usr.sbin/ncrcontrol/Makefile
@@ -0,0 +1,8 @@
+PROG= ncrcontrol
+SRCS= ncrcontrol.c
+
+CFLAGS+= -I/sys
+LDADD+= -lkvm
+DPADD+= ${DESTDIR}/usr/lib/libkvm.a
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ncrcontrol/ncrcontrol.1 b/usr.sbin/ncrcontrol/ncrcontrol.1
new file mode 100644
index 0000000..11505f0
--- /dev/null
+++ b/usr.sbin/ncrcontrol/ncrcontrol.1
@@ -0,0 +1,286 @@
+.\" Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: ncrcontrol.8,v 1.1 94/10/09 21:25:51 wolf Exp $
+.\"
+.Dd September 16, 1994
+.Dt NCRCONTROL 8
+.Os FreeBSD
+.Sh NAME
+.Nm ncrcontrol
+.Nd manually configure the ncr810/825 PCI/SCSI device driver
+.Sh SYNOPSIS
+.\"--------------------------------------------------------
+.\" ncrcontrol [-Mcore] [-Nsystem] [-u unit] [-v] [-v] -i
+.\"--------------------------------------------------------
+.Nm ncrcontrol
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Op Fl u Ar unit
+.Op Fl v
+.Op Fl v
+.Fl i
+.\"--------------------------------------------------------
+.\" ncrcontrol [-N system] [-u unit] [-p wait]
+.\"--------------------------------------------------------
+.Nm ncrcontrol
+.Op Fl N Ar system
+.Op Fl u Ar unit
+.Op Fl p Ar wait
+.\"------------------------------------------------------------
+.\" ncrcontrol [-Nsystem] [-u unit] [-t target] -s name=value
+.\"------------------------------------------------------------
+.Nm ncrcontrol
+.Op Fl N Ar system
+.Op Fl u Ar unit
+.Op Fl t Ar target
+.Fl s
+.Ar name=value
+.\"------------------------------------------------------------
+.\" ncrcontrol [-Mcore] [-Nsystem] [-u unit] [-t target] -d pattern
+.\"------------------------------------------------------------
+.Nm ncrcontrol
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Op Fl u Ar unit
+.Op Fl t Ar target
+.Fl d
+.Ar debug
+.\"------------------------------------------------------------
+.\" ncrcontrol [-Nsystem] [-u unit] -w -k torture
+.\"------------------------------------------------------------
+.Nm ncrcontrol
+.Op Fl N Ar system
+.Op Fl u Ar unit
+.Fl w
+.Fl k
+.Ar torture
+.\"
+.\"=====================================================================
+.\"
+.Sh DESCRIPTION
+The
+.Nm ncrcontrol
+command symbolically displays the contents of the ncr810/ncr825
+pci/scsi driver control structure.
+There are a number of output formats,
+depending on the options for the information presented.
+It may be used to set some values, too.
+
+.\"--------------------------------------------------------
+.\" ncrcontrol [-Mcore] [-Nsystem] [-u unit] [-v] [-v] -i
+.\"--------------------------------------------------------
+The first form of the command displays an overview of the
+connected targets. The
+.Fl v
+requests a verbose output.
+
+.\"--------------------------------------------------------
+.\" ncrcontrol [-N system] [-u unit] [-p wait]
+.\"--------------------------------------------------------
+Using the second form, with a
+.Ar wait
+interval specified,
+.Nm ncrcontrol
+will continuously display the information regarding data
+traffic on the selected scsi bus.
+
+.\"------------------------------------------------------------
+.\" ncrcontrol [-Nsystem] [-u unit] [-t target] -s name=value
+.\"------------------------------------------------------------
+The third form sets a configuration value for one or all
+targets of a selected scsi bus.
+It normally is not needed, if the device driver options are
+correctly set in kernel configuration.
+
+.\"------------------------------------------------------------
+.\" ncrcontrol [-M core] [-N system] [-u unit] [-t target] -w -d pattern
+.\"------------------------------------------------------------
+The forth form presents the content of the drivers control
+structure. By the
+.Ar pattern
+certain parts of the output can be enabled/disabled.
+It's only used to debug the driver.
+
+.\"------------------------------------------------------------
+.\" ncrcontrol [-N system] [-u unit] -w -k torture
+.\"------------------------------------------------------------
+With the last form certain driver problems can be forced.
+THIS MAY CRASH YOUR SYSTEM.
+It's only used to debug the driver.
+
+.\"
+.\"=====================================================================
+.\"
+.Pp
+The options have the following meaning:
+.Bl -tag -width flag
+.\"------------------------------------------------------------
+.\" -d pattern
+.\"------------------------------------------------------------
+.It Fl d
+Show the content of the drivers control structure.
+The
+.Ar pattern
+selects the fields, which are displayed. With
+.Fl d?
+you can get a list of valid flags.
+
+.\"------------------------------------------------------------
+.\" -i
+.\"------------------------------------------------------------
+.It Fl i
+Show the configuration state of the connected targets.
+With the
+.Fl v
+option you can request a more verbose information.
+
+.\"------------------------------------------------------------
+.\" -k torture
+.\"------------------------------------------------------------
+.It Fl k
+Force certain driver problems to check the error recovery
+functions. This option should only be used by the developers.
+With
+.Fl k?
+you can get a list of possible tortures.
+This option requires the
+.Fl w
+option to be set.
+
+.\"------------------------------------------------------------
+.\" -M core
+.\"------------------------------------------------------------
+.It Fl M
+Extract values associated with the name list from the specified core
+instead of the default
+.Pa /dev/kmem .
+.\"------------------------------------------------------------
+.\" -N system
+.\"------------------------------------------------------------
+.It Fl N
+Extract the name list from the specified system instead of the default
+.Pa /386bsd .
+
+.\"------------------------------------------------------------
+.\" -p wait
+.\"------------------------------------------------------------
+When
+.Nm ncrcontrol
+is invoked with a
+.Ar wait
+interval argument, it displays a running count of statistics related to
+the transfers on the selected scsi bus.
+
+This display consists of the number of transfers and number of transferred
+byted for the controller and for each connected target.
+
+(NOT YET COMPLETE)
+
+.\"------------------------------------------------------------
+.\" -s field=value
+.\"------------------------------------------------------------
+.It Fl s
+Set a configuration value for one or more targets.
+One ore more targets can be selected by the
+.Fl t
+option. If no target is selected, then the field is set
+for all connect targets.
+
+(NOT YET COMPLETE)
+
+.\"------------------------------------------------------------
+.\" -t target
+.\"------------------------------------------------------------
+.It Fl t
+Select the target for the
+.Fl s
+option. This option may be given more than one time.
+
+.\"------------------------------------------------------------
+.\" -u unit
+.\"------------------------------------------------------------
+.It Fl u
+Select the controller unit.
+If this option is not given, then controller 0 is assumed.
+Most systems have only one controller.
+
+.\"------------------------------------------------------------
+.\" -v
+.\"------------------------------------------------------------
+.It Fl v
+Enable verbose output for the
+.Fl i
+option.
+
+.\"------------------------------------------------------------
+.\" -w
+.\"------------------------------------------------------------
+.It Fl w
+Wizard option.
+Enable the usage of the
+.Fl k
+option.
+
+.\"
+.\"=====================================================================
+.\"
+.Pp
+(NOT YET COMPLETE)
+
+.\"
+.\"=====================================================================
+.\"
+.Sh SEE ALSO
+.Xr scsi 5
+
+.\"
+.\"=====================================================================
+.\"
+.Sh HISTORY
+The
+.Nm ncrcontrol
+command was hacked for
+.Bx 386
+and ported to version 1.1 of
+.Bx Free
+by Wolfgang Stanglmeier <wolf@dentaro.GUN.de>.
+It was ported to
+.Bx Net
+by Charles M. Hannum <mycroft@gnu.ai.mit.edu>
+and to version 2.0 of
+.Bx Free
+by Stefan Esser <se@zpr.Uni-Koeln.DE>.
+
+.\"
+.\"=====================================================================
+.\"
+.Sh BUGS
+The
+.Nm ncrcontrol
+was hacked as a debugging tool for the ncr810 driver.
+It should be deleted sometimes.
+There should be a general tool to change device driver options
+on the fly.
+The statistical data should be gathered by the generic scsi driver.
diff --git a/usr.sbin/ncrcontrol/ncrcontrol.c b/usr.sbin/ncrcontrol/ncrcontrol.c
new file mode 100644
index 0000000..fa81390
--- /dev/null
+++ b/usr.sbin/ncrcontrol/ncrcontrol.c
@@ -0,0 +1,1630 @@
+/**************************************************************************
+**
+** $Id: ncrcontrol.c,v 1.1 1994/10/12 02:23:14 se Exp $
+**
+** Utility for NCR 53C810 device driver.
+**
+** 386bsd / FreeBSD / NetBSD
+**
+**-------------------------------------------------------------------------
+**
+** Written for 386bsd and FreeBSD by
+** wolf@dentaro.gun.de Wolfgang Stanglmeier
+** se@mi.Uni-Koeln.de Stefan Esser
+**
+** Ported to NetBSD by
+** mycroft@gnu.ai.mit.edu
+**
+**-------------------------------------------------------------------------
+**
+** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+**
+***************************************************************************
+*/
+
+#include <sys/file.h>
+#include <sys/types.h>
+#ifdef __NetBSD__
+#include <sys/device.h>
+#endif
+#include <nlist.h>
+#include <stdio.h>
+#include <errno.h>
+#include <paths.h>
+#include <limits.h>
+#include <kvm.h>
+#include <i386/pci/ncr.c>
+
+/*
+** used external functions
+*/
+
+#if defined(__NetBSD__) || (__FreeBSD__ >= 2)
+kvm_t *kvm;
+#define KVM_NLIST(n) (kvm_nlist(kvm, (n)) >= 0)
+#define KVM_READ(o, p, l) (kvm_read(kvm, (o), (void*)(p), (l)) == (l))
+#else
+#define KVM_NLIST(n) (kvm_nlist((n)) >= 0)
+#define KVM_READ(o, p, l) (kvm_read((void*)(o), (p), (l)) == (l))
+#endif
+
+extern void exit();
+extern char* strerror (int num);
+
+/*===========================================================
+**
+** Global variables.
+**
+**===========================================================
+*/
+
+char *prog;
+u_long verbose;
+u_long wizard;
+
+
+
+struct nlist nl[] = {
+#define N_NCR_VERSION 0
+ { "_ncr_version" },
+#ifdef __NetBSD__
+#define N_NCRCD 1
+ { "_ncrcd" },
+#else
+#define N_NCRP 1
+ { "_ncrp" },
+#define N_NNCR 2
+ { "_nncr" },
+#endif
+ { 0 }
+};
+
+
+char *vmunix = _PATH_UNIX;
+char *kmemf = NULL;
+
+int kvm_isopen;
+
+u_long ncr_base;
+u_long lcb_base;
+u_long ccb_base;
+
+u_long ncr_unit;
+#ifdef __NetBSD__
+struct cfdriver ncrcd;
+#else
+u_long ncr_units;
+#endif
+
+struct ncb ncr;
+struct lcb lcb;
+struct ccb ccb;
+
+u_long target_mask;
+u_long global_lun_mask;
+u_long lun_mask;
+u_long interval;
+
+/*===========================================================
+**
+** Accessing kernel memory via kvm library.
+**
+**===========================================================
+*/
+
+read_ccb(u_long base)
+{
+ ccb_base = base;
+ if (!KVM_READ (
+ base,
+ &ccb,
+ sizeof (struct ccb))) {
+ fprintf (stderr, "%s: bad kvm read at %x.\n", prog, base);
+ exit (1);
+ };
+}
+
+read_lcb(u_long base)
+{
+ lcb_base = base;
+ if (!KVM_READ (
+ base,
+ &lcb,
+ sizeof (struct lcb))) {
+ fprintf (stderr, "%s: bad kvm read at %x.\n", prog, base);
+ exit (1);
+ };
+}
+
+read_ncr()
+{
+ if (!KVM_READ (
+ ncr_base,
+ &ncr,
+ sizeof (ncr))) {
+ fprintf (stderr, "%s: bad kvm read at %x.\n", prog, ncr_base);
+ exit (1);
+ };
+}
+
+void open_kvm(int flags)
+{
+ int i;
+ u_long kernel_version;
+#if defined(__NetBSD__) || (__FreeBSD__ >= 2)
+ char errbuf[_POSIX2_LINE_MAX];
+#endif
+
+ if (kvm_isopen) return;
+
+#if defined(__NetBSD__) || (__FreeBSD__ >= 2)
+ kvm = kvm_openfiles(vmunix, kmemf, NULL, flags, errbuf);
+ if (kvm == NULL) {
+ fprintf(stderr, "%s: kvm_openfiles: %s\n", prog, errbuf);
+ exit(1);
+ }
+#else
+ if (kvm_openfiles(vmunix, kmemf, NULL) == -1) {
+ fprintf(stderr, "%s: kvm_openfiles: %s\n", prog, kvm_geterr());
+ exit(1);
+ }
+#endif
+
+ if (!KVM_NLIST(nl)) {
+ fprintf(stderr, "%s: no symbols in \"%s\".\n",
+ prog, vmunix);
+ exit (2);
+ };
+
+ for (i=0; nl[i].n_name; i++)
+ if (nl[i].n_type == 0) {
+ fprintf(stderr, "%s: no symbol \"%s\" in \"%s\".\n",
+ prog, nl[i].n_name, vmunix);
+ exit(1);
+ }
+
+ if (!KVM_READ (
+ nl[N_NCR_VERSION].n_value,
+ &kernel_version,
+ sizeof (kernel_version))) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ };
+
+ if (kernel_version != ncr_version){
+ fprintf (stderr, "%s: incompatible with kernel. Rebuild!\n",
+ prog);
+ exit (1);
+ };
+
+#ifdef __NetBSD__
+
+ if (!KVM_READ (
+ nl[N_NCRCD].n_value,
+ &ncrcd,
+ sizeof (ncrcd))) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ };
+
+ if (ncr_unit >= ncrcd.cd_ndevs){
+ fprintf (stderr, "%s: bad unit number (valid range: 0-%d).\n",
+ prog, ncrcd.cd_ndevs-1);
+ exit (1);
+ };
+
+ if (!KVM_READ (
+ ncrcd.cd_devs+4*ncr_unit,
+ &ncr_base,
+ sizeof (ncr_base))) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ };
+
+ if (!ncr_base) {
+ fprintf (stderr,
+ "%s: control structure not allocated (not found in autoconfig?)\n", prog);
+ exit (1);
+ };
+
+#else /* !__NetBSD__ */
+
+ if (!KVM_READ (
+ nl[N_NNCR].n_value,
+ &ncr_units,
+ sizeof (ncr_units))) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ };
+
+ if (ncr_unit >= ncr_units){
+ fprintf (stderr, "%s: bad unit number (valid range: 0-%d).\n",
+ prog, ncr_units-1);
+ exit (1);
+ };
+
+ if (!KVM_READ (
+ nl[N_NCRP].n_value+4*ncr_unit,
+ &ncr_base,
+ sizeof (ncr_base))) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ };
+
+ if (!ncr_base) {
+ fprintf (stderr,
+ "%s: control structure not allocated (not found in autoconfig?)\n", prog);
+ exit (1);
+ };
+
+#endif /* !__NetBSD__ */
+
+ read_ncr();
+
+ if (!ncr.vaddr) {
+ fprintf (stderr,
+ "%s: 53c810 not mapped (not found in autoconfig?)\n", prog);
+ exit (1);
+ };
+
+ kvm_isopen = 1;
+}
+
+
+
+
+void set_target_mask(void)
+{
+ int t;
+ if (target_mask) return;
+ for (t=0; t<MAX_TARGET; t++)
+ if (ncr.target[t].jump_tcb.l_cmd) target_mask |= (1<<t);
+}
+
+void set_lun_mask(struct tcb * tp)
+{
+ int l;
+ lun_mask = global_lun_mask;
+ if (lun_mask) return;
+ for (l=0; l<MAX_LUN; l++)
+ if (tp->lp[l]) lun_mask |= (1<<l);
+}
+
+void printc (u_char*p, int l)
+{
+ for (;l>0;l--) {
+ char c=*p++;
+ printf ("%c", c?c:'_');
+ }
+}
+
+/*================================================================
+**
+**
+** system info
+**
+**
+**================================================================
+*/
+
+do_info(void)
+{
+ int t,l,i,d,f,fl;
+ struct tcb * tip;
+ open_kvm(O_RDONLY);
+
+ if (verbose>=3)
+ printf ("ncr unit=%d data@%x register@%x (pci@%x)\n\n",
+ ncr_unit, ncr_base, ncr.vaddr, ncr.paddr);
+
+ set_target_mask();
+
+ printf ("T:L Vendor Device Rev Speed Max Wide Tags\n");
+ for (t=0; t<MAX_TARGET;t++) {
+ if (!((target_mask>>t)&1)) continue;
+ tip = &ncr.target[t];
+
+ set_lun_mask(tip);
+ if (!lun_mask) lun_mask=1;
+ fl=1;
+
+ for (l=0; l<MAX_LUN; l++) {
+ if (!((lun_mask>>l)&1)) continue;
+
+ printf ("%d:%d ", t, l);
+
+ if (!tip->jump_tcb.l_cmd) break;
+
+ if (fl) {
+ fl=0;
+ printc (&tip->inqdata[ 8], 8);printf(" ");
+ printc (&tip->inqdata[16],16);printf(" ");
+ printc (&tip->inqdata[32], 4);printf(" ");
+
+ if (tip->period==0xffff) {
+ printf ("asyn");
+ } else if (tip->period) {
+ printf ("%4.1f", 1000.0 / tip->period);
+ } else {
+ printf (" ?");
+ }
+
+ printf (" ");
+
+ if (tip->minsync==255) {
+ printf ("asyn");
+ } else if (tip->minsync) {
+ printf ("%4.1f", 250.0 / tip->minsync);
+ } else {
+ printf (" ?");
+ }
+ } else printf (" ");
+
+ if (!tip->lp[l]) {
+ printf (" no\n");
+ continue;
+ };
+ read_lcb ((u_long) tip->lp[l]);
+
+ switch (tip->widedone) {
+ case 1:
+ printf (" 8");
+ break;
+ case 2:
+ printf (" 16");
+ break;
+ case 3:
+ printf (" 32");
+ break;
+ default:
+ printf (" ?");
+ };
+
+ if (lcb.usetags)
+ printf ("%5d", lcb.actlink);
+ else
+ printf (" -");
+
+ printf ("\n");
+
+ };
+
+ if (!tip->jump_tcb.l_cmd) {
+ printf (" --- no target.\n");
+ continue;
+ };
+
+ if (verbose<1) continue;
+
+ for (i=0; i<8; i++) {
+ char* (class[10])={
+ "disk","tape","printer","processor",
+ "worm", "cdrom", "scanner", "optical disk",
+ "media changer", "communication device"};
+ d = tip->inqdata[i];
+ printf ("[%02x]: ",d);
+
+ switch (i) {
+
+ case 0:
+ f = d & 0x1f;
+ if (f<10) printf (class[f]);
+ else printf ("unknown (%x)", f);
+ break;
+ case 1:
+ f = (d>>7) & 1;
+ if (f) printf ("removable media");
+ else printf ("fixed media");
+ break;
+
+ case 2:
+ f = d & 7;
+ switch (f) {
+ case 0: printf ("SCSI-1");
+ break;
+ case 1: printf ("SCSI-1 with CCS");
+ break;
+ case 2: printf ("SCSI-2");
+ break;
+ default:
+ printf ("unknown ansi version (%d)",
+ f);
+ }
+ break;
+
+ case 3:
+ if (d&0xc0) printf ("capabilities:");
+ if (d&0x80) printf (" AEN");
+ if (d&0x40) printf (" TERMINATE-I/O");
+ break;
+
+ case 7:
+ if (d&0xfb) printf ("capabilities:");
+ if (d&0x80) printf (" relative");
+ if (d&0x40) printf (" wide32");
+ if (d&0x20) printf (" wide");
+ if (d&0x10) printf (" synch");
+ if (d&0x08) printf (" link");
+ if (d&0x02) printf (" tags");
+ if (d&0x01) printf (" soft-reset");
+ };
+ printf ("\n");
+ };
+ printf ("\n");
+ };
+ printf ("\n");
+#ifndef __NetBSD__
+ if (ncr.imask) {
+ u_short v;
+ printf ("Interrupt vector is");
+ if (ncr.imask & (ncr.imask-1))
+ printf (" one of the following:");
+ for (v=15;v>0;v--)
+ if ((ncr.imask>>v)&1)
+ printf (" %d",v);
+ printf (".\n\n");
+ };
+#endif
+}
+
+/*================================================================
+**
+**
+** profiling
+**
+**
+**================================================================
+*/
+
+do_profile(void)
+{
+#define old backup.profile
+#define new ncr.profile
+
+ struct ncb backup;
+ struct profile diff;
+ int tra,line,t;
+
+ open_kvm(O_RDONLY);
+
+ set_target_mask();
+
+ if (interval<1) interval=1;
+ for (;;) {
+ /*
+ ** Header Line 1
+ */
+ printf (" total ");
+
+ for (t=0; t<MAX_TARGET; t++) {
+ if (!((target_mask>>t)&1)) continue;
+ printf (" ");
+ printc (&ncr.target[t].inqdata[16],8);
+ };
+
+ printf (" transf. disconn interru");
+
+ if (verbose>=1) printf (" ---- ms/transfer ----");
+
+ printf ("\n");
+
+ /*
+ ** Header Line 2
+ */
+
+ printf ("t/s kb/s ");
+
+ for (t=0; t<MAX_TARGET; t++) {
+ if (!((target_mask>>t)&1)) continue;
+ printf (" t/s kb/s");
+ };
+
+ printf (" length exp une fly brk");
+
+ if (verbose>=1) printf (" total pre post disc");
+
+ printf ("\n");
+
+ /*
+ ** Data
+ */
+
+ for(line=0;line<20;line++) {
+ backup = ncr;
+ read_ncr();
+ diff.num_trans = new.num_trans - old.num_trans;
+ diff.num_bytes = new.num_bytes - old.num_bytes;
+ diff.num_fly = new.num_fly - old.num_fly ;
+ diff.num_int = new.num_int - old.num_int ;
+ diff.ms_setup = new.ms_setup - old.ms_setup;
+ diff.ms_data = new.ms_data - old.ms_data;
+ diff.ms_disc = new.ms_disc - old.ms_disc;
+ diff.ms_post = new.ms_post - old.ms_post;
+ diff.num_disc = new.num_disc - old.num_disc;
+ diff.num_break = new.num_break - old.num_break;
+
+ tra = diff.num_trans;
+ if (!tra) tra=1;
+
+ printf ("%3.0f %4.0f ",
+ (1.0 * diff.num_trans) / interval,
+ (1.0 * diff.num_bytes) / (1024*interval));
+
+
+ for (t=0; t<MAX_TARGET; t++) {
+ if (!((target_mask>>t)&1)) continue;
+ printf (" %3.0f %4.0f",
+ ((ncr.target[t].transfers-
+ backup.target[t].transfers)*1.0)
+ /interval,
+ ((ncr.target[t].bytes-
+ backup.target[t].bytes)*1.0)
+ /(1024*interval));
+ };
+
+ printf ("%7.0f ", (diff.num_bytes*1.0) / tra);
+
+ printf (" %4.0f", (1.0*(diff.num_disc-diff.num_break))
+ /interval);
+
+ printf ("%4.0f", (1.0*diff.num_break)/interval);
+
+ printf ("%4.0f", (1.0*diff.num_fly) / interval);
+
+ printf ("%4.0f", (1.0*diff.num_int) / interval);
+
+ if (verbose >= 1) {
+ printf ("%7.1f",
+ (diff.ms_disc+diff.ms_data+diff.ms_setup+diff.ms_post)
+ * 1.0 / tra);
+
+ printf ("%5.1f%5.1f%6.1f",
+ 1.0 * diff.ms_setup / tra,
+ 1.0 * diff.ms_post / tra,
+ 1.0 * diff.ms_disc / tra);
+ };
+
+ printf ("\n");
+ fflush (stdout);
+ sleep (interval);
+ };
+ };
+}
+
+/*================================================================
+**
+**
+** Port access
+**
+**
+**================================================================
+*/
+
+static int kernelwritefile;
+static char* kernelwritefilename = _PATH_KMEM;
+
+void openkernelwritefile(void)
+{
+ if (kernelwritefile) return;
+
+ kernelwritefile = open (kernelwritefilename, O_WRONLY);
+ if (kernelwritefile<3) {
+ fprintf (stderr, "%s: %s: %s\n",
+ prog, kernelwritefilename, strerror(errno));
+ exit (1);
+ };
+}
+
+void out (u_char reg, u_char val)
+{
+ u_long addr = ncr.vaddr + reg;
+ openkernelwritefile();
+ if (lseek (kernelwritefile, addr, 0) != addr) {
+ fprintf (stderr, "%s: %s: %s\n",
+ prog, kernelwritefilename, strerror(errno));
+ exit (1);
+ }
+ if (write (kernelwritefile, &val, 1) < 0) {
+ fprintf (stderr, "%s: %s: %s\n",
+ prog, kernelwritefilename, strerror(errno));
+ exit (1);
+ };
+}
+
+u_char in (u_char reg)
+{
+ u_char res;
+ if (!KVM_READ (
+ (ncr.vaddr + reg),
+ &res,
+ 1)) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ }
+ return (res);
+}
+
+/*================================================================
+**
+**
+** Setting of driver parameters
+**
+**
+**================================================================
+*/
+
+void do_set (char * arg)
+{
+ struct usrcmd user;
+ u_long addr;
+ int i;
+
+ open_kvm(O_RDWR);
+ addr = ncr_base + offsetof (struct ncb, user);
+
+ for (i=3; i; i--) {
+ if (!KVM_READ (
+ (addr),
+ &user,
+ sizeof (user))) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ }
+ if (!user.cmd) break;
+ sleep (1);
+ }
+ if (user.cmd) {
+ fprintf (stderr, "%s: ncb.user busy.\n", prog);
+ exit (1);
+ };
+
+ user.target = target_mask;
+ user.lun = lun_mask;
+ user.data = 0;
+ user.cmd = 0;
+
+ if (!strcmp(arg, "?")) { printf (
+"async: disable synchronous transfers.\n"
+"sync=value: set the maximal synchronous transfer rate (MHz).\n"
+"fast: set FAST SCSI-2.\n"
+"\n"
+"wide=value: set the bus width (0=8bit 1=16bit).\n"
+"\n"
+"tags=value: use this number of tags.\n"
+"orderedtag: use ordered tags only.\n"
+"simpletag: use simple tags only.\n"
+"orderedwrite: use simple tags for read, else ordered tags.\n"
+"\n"
+"debug=value: set debug mode.\n"
+"\n");
+ return;
+ };
+
+ if (!strcmp(arg, "async")) {
+ user.data = 255;
+ user.cmd = UC_SETSYNC;
+ };
+
+ if (!strcmp(arg, "fast")) {
+ user.data = 25;
+ user.cmd = UC_SETSYNC;
+ };
+
+ if (!strncmp(arg, "sync=", 5)) {
+ float f = strtod (arg+5, NULL);
+ if (f>=4.0 && f<=10.0) {
+ user.data = 250.0 / f;
+ user.cmd = UC_SETSYNC;
+ };
+ };
+
+ if (!strncmp(arg, "wide=", 5)) {
+ u_char t = strtoul (arg+5, (char**)0, 0);
+ if (t<=1) {
+ user.data = t;
+ user.cmd = UC_SETWIDE;
+ };
+ };
+
+ if (!strncmp(arg, "tags=", 5)) {
+ u_char t = strtoul (arg+5, (char**)0, 0);
+ if (t<=MAX_TAGS) {
+ user.data = t;
+ user.cmd = UC_SETTAGS;
+ };
+ };
+
+ if (!strncmp(arg, "flags=", 6)) {
+ u_char t = strtoul (arg+6, (char**)0, 0);
+ if (t<=0xff) {
+ user.data = t;
+ user.cmd = UC_SETFLAG;
+ };
+ };
+
+ if (!strncmp(arg, "debug=", 6)) {
+ user.data = strtoul (arg+6, (char**)0, 0);
+ user.cmd = UC_SETDEBUG;
+ };
+
+ if (!strcmp(arg, "orderedtag")) {
+ user.data = M_ORDERED_TAG;
+ user.cmd = UC_SETORDER;
+ };
+
+ if (!strcmp(arg, "simpletag")) {
+ user.data = M_SIMPLE_TAG;
+ user.cmd = UC_SETORDER;
+ };
+
+ if (!strcmp(arg, "orderedwrite")) {
+ user.data = 0;
+ user.cmd = UC_SETORDER;
+ };
+
+ if (user.cmd) {
+ openkernelwritefile();
+
+ if (lseek (kernelwritefile, addr, 0) != addr) {
+ fprintf (stderr, "%s: %s: %s\n",
+ prog, kernelwritefilename, strerror(errno));
+ exit (1);
+ }
+ if (write (kernelwritefile, &user, sizeof (user)) < 0) {
+ fprintf (stderr, "%s: %s: %s\n",
+ prog, kernelwritefilename, strerror(errno));
+ exit (1);
+ }
+
+ return;
+ };
+
+ fprintf (stderr, "%s: do_set \"%s\" not (yet) implemented.\n",
+ prog, arg);
+}
+
+/*================================================================
+**
+**
+** D O _ K I L L
+**
+**
+**================================================================
+*/
+
+do_kill(char * arg)
+{
+ open_kvm(O_RDWR);
+
+ if (!strcmp(arg, "?")) { printf (
+"scsireset: force SCSI bus reset.\n"
+"scriptabort: send an abort cmd to the script processor.\n"
+"scriptstart: start script processind (set SIGP bit).\n"
+"evenparity: force even parity.\n"
+"oddparity: force odd parity.\n"
+"noreselect: disable reselect (force timeouts).\n"
+"doreselect: enable reselect.\n"
+"\n");
+ return;
+ };
+
+ if (!wizard) {
+ fprintf (stderr, "%s: You are NOT a wizard!\n", prog);
+ exit (2);
+ };
+
+ if (!strcmp(arg, "scsireset")) {
+ out (0x01, 0x08);
+ out (0x01, 0x00);
+ return;
+ };
+ if (!strcmp(arg, "scriptabort")) {
+ out (0x14, 0x80);
+ out (0x14, 0x20);
+ return;
+ };
+ if (!strcmp(arg, "scriptstart")) {
+ out (0x14, 0x20);
+ return;
+ };
+ if (!strcmp(arg, "evenparity")) {
+ out (0x01, 0x04);
+ return;
+ };
+ if (!strcmp(arg, "oddparity")) {
+ out (0x01, 0x00);
+ return;
+ };
+ if (!strcmp(arg, "noreselect")) {
+ out (0x04, in (0x04) & ~RRE);
+ return;
+ };
+ if (!strcmp(arg, "doreselect")) {
+ out (0x04, in (0x04) | RRE);
+ return;
+ };
+ fprintf (stderr, "%s: do_kill \"%s\" not (yet) implemented.\n",
+ prog, arg);
+}
+
+/*================================================================
+**
+**
+** Write debug info: utilities: write symbolname.
+**
+**
+**================================================================
+*/
+
+static const char * sn (u_long a)
+{
+ static char buffer[100];
+
+ const char * s="";
+ u_long d,m;
+
+ a -= ncr.p_script;
+ m = sizeof (struct script);
+
+ if ((d=a-offsetof(struct script, start))<m) m=d, s="<start>";
+ if ((d=a-offsetof(struct script, start1))<m) m=d, s="<start1>";
+ if ((d=a-offsetof(struct script, startpos))<m) m=d, s="<startpos>";
+ if ((d=a-offsetof(struct script, tryloop))<m) m=d, s="<tryloop>";
+ if ((d=a-offsetof(struct script, trysel))<m) m=d, s="<trysel>";
+ if ((d=a-offsetof(struct script, skip))<m) m=d, s="<skip>";
+ if ((d=a-offsetof(struct script, skip2))<m) m=d, s="<skip2>";
+ if ((d=a-offsetof(struct script, idle))<m) m=d, s="<idle>";
+ if ((d=a-offsetof(struct script, select))<m) m=d, s="<select>";
+ if ((d=a-offsetof(struct script, prepare))<m) m=d, s="<prepare>";
+ if ((d=a-offsetof(struct script, loadpos))<m) m=d, s="<loadpos>";
+ if ((d=a-offsetof(struct script, prepare2))<m) m=d, s="<prepare2>";
+ if ((d=a-offsetof(struct script, setmsg))<m) m=d, s="<setmsg>";
+ if ((d=a-offsetof(struct script, clrack))<m) m=d, s="<clrack>";
+ if ((d=a-offsetof(struct script, dispatch))<m) m=d, s="<dispatch>";
+ if ((d=a-offsetof(struct script, checkatn))<m) m=d, s="<checkatn>";
+ if ((d=a-offsetof(struct script, command))<m) m=d, s="<command>";
+ if ((d=a-offsetof(struct script, status))<m) m=d, s="<status>";
+ if ((d=a-offsetof(struct script, msg_in))<m) m=d, s="<msg_in>";
+ if ((d=a-offsetof(struct script, msg_bad))<m) m=d, s="<msg_bad>";
+ if ((d=a-offsetof(struct script, msg_parity))<m) m=d, s="<msg_parity>";
+ if ((d=a-offsetof(struct script, msg_reject))<m) m=d, s="<msg_reject>";
+ if ((d=a-offsetof(struct script, msg_extended))<m) m=d, s="<msg_extended>";
+ if ((d=a-offsetof(struct script, msg_sdtr))<m) m=d, s="<msg_sdtr>";
+ if ((d=a-offsetof(struct script, complete))<m) m=d, s="<complete>";
+ if ((d=a-offsetof(struct script, cleanup))<m) m=d, s="<cleanup>";
+ if ((d=a-offsetof(struct script, cleanup0))<m) m=d, s="<cleanup>";
+ if ((d=a-offsetof(struct script, signal))<m) m=d, s="<signal>";
+ if ((d=a-offsetof(struct script, save_dp))<m) m=d, s="<save_dp>";
+ if ((d=a-offsetof(struct script, restore_dp))<m) m=d, s="<restore_dp>";
+ if ((d=a-offsetof(struct script, disconnect))<m) m=d, s="<disconnect>";
+ if ((d=a-offsetof(struct script, msg_out))<m) m=d, s="<msg_out>";
+ if ((d=a-offsetof(struct script, msg_out_done))<m) m=d, s="<msg_out_done>";
+ if ((d=a-offsetof(struct script, msg_out_abort))<m) m=d, s="<msg_out_abort>";
+ if ((d=a-offsetof(struct script, getcc))<m) m=d, s="<getcc>";
+ if ((d=a-offsetof(struct script, getcc1))<m) m=d, s="<getcc1>";
+ if ((d=a-offsetof(struct script, getcc2))<m) m=d, s="<getcc2>";
+ if ((d=a-offsetof(struct script, badgetcc))<m) m=d, s="<badgetcc>";
+ if ((d=a-offsetof(struct script, reselect))<m) m=d, s="<reselect>";
+ if ((d=a-offsetof(struct script, reselect2))<m) m=d, s="<reselect2>";
+ if ((d=a-offsetof(struct script, resel_tmp))<m) m=d, s="<resel_tmp>";
+ if ((d=a-offsetof(struct script, resel_lun))<m) m=d, s="<resel_lun>";
+ if ((d=a-offsetof(struct script, resel_tag))<m) m=d, s="<resel_tag>";
+ if ((d=a-offsetof(struct script, data_in))<m) m=d, s="<data_in>";
+ if ((d=a-offsetof(struct script, data_out))<m) m=d, s="<data_out>";
+ if ((d=a-offsetof(struct script, no_data))<m) m=d, s="<no_data>";
+ if ((d=a-offsetof(struct script, aborttag))<m) m=d, s="<aborttag>";
+ if ((d=a-offsetof(struct script, abort))<m) m=d, s="<abort>";
+
+ if (!*s) return s;
+
+ sprintf (buffer, "%s:%d%c", s, m/4, 0);
+ return (buffer);
+}
+
+/*================================================================
+**
+**
+** Write debug info: utilities: write misc. fields.
+**
+**
+**================================================================
+*/
+
+static void printm (u_char * msg, int len)
+{
+ u_char l;
+ do {
+ if (*msg==M_EXTENDED)
+ l=msg[1]+2;
+ else if ((*msg & 0xf0)==0x20)
+ l=2;
+ else l=1;
+ len-=l;
+
+ printf (" %x",*msg++);
+ while (--l>0) printf ("-%x",*msg++);
+ } while (len>0);
+}
+
+void dump_table (const char * str, struct scr_tblmove * p, int l)
+{
+ int i;
+ for (i=0;l>0;i++,p++,l--) if (p->size) {
+ printf (" %s[%d]: %5d @ 0x%08x\n",
+ str, i, p->size, p->addr);
+ };
+}
+
+void dump_link (const char* name, struct link * link)
+{
+ printf ("%s: cmd=%08x pa=%08x %s\n",
+ name, link->l_cmd, link->l_paddr, sn(link->l_paddr));
+}
+
+/*================================================================
+**
+**
+** Write debug info: utilities: write time fields.
+**
+**
+**================================================================
+*/
+
+void dump_tstamp (const char* name, struct tstamp * p)
+#define P(id,fld)\
+ if (p->fld.tv_sec) \
+ printf ("%s: "id" at %s.%06d",\
+ name,ctime(&p->fld.tv_sec),p->fld.tv_usec);
+{
+ P ("started ", start);
+ P ("ended ", end );
+ P ("selected ", select);
+ P ("command ", command);
+ P ("data ", data);
+ P ("status ", status);
+ P ("disconnected", disconnect);
+ P ("reselected ", reselect);
+ printf ("\n");
+}
+
+
+
+
+void dump_profile (const char* name, struct profile * p)
+{
+ printf ("%s: %10d transfers.\n" ,name,p->num_trans);
+ printf ("%s: %10d bytes transferred.\n",name,p->num_bytes);
+ printf ("%s: %10d disconnects.\n" ,name,p->num_disc);
+ printf ("%s: %10d short transfers.\n" ,name,p->num_break);
+ printf ("%s: %10d interrupts.\n" ,name,p->num_int);
+ printf ("%s: %10d on the fly ints.\n" ,name,p->num_fly);
+ printf ("%s: %10d ms setup time.\n" ,name,p->ms_setup);
+ printf ("%s: %10d ms data transfer.\n" ,name,p->ms_data);
+ printf ("%s: %10d ms disconnected.\n" ,name,p->ms_disc);
+ printf ("%s: %10d ms postprocessing.\n",name,p->ms_post);
+ printf ("\n");
+}
+
+/*================================================================
+**
+**
+** Write debug info: utilities: write script registers.
+**
+**
+**================================================================
+*/
+
+static void dump_reg(struct ncr_reg * rp)
+{
+ u_char *reg = (u_char*) rp;
+#define l(i) (reg[i]+(reg[i+1]<<8ul)+(reg[i+2]<<16ul)+(reg[i+3]<<24ul))
+ int ad;
+
+ char*(phasename[8])={"DATA-OUT","DATA-IN","COMMAND","STATUS",
+ "ILG-OUT","ILG-IN","MESSAGE-OUT","MESSAGE-IN"};
+ for (ad=0x00;ad<0x80;ad++) {
+ switch (ad % 16) {
+
+ case 0:
+ printf (" %02x:\t",ad);
+ break;
+ case 8:
+ printf (" : ");
+ break;
+ default:
+ printf (" ");
+ };
+ printf ("%02x", reg[ad]);
+ if (ad % 16 == 15) printf ("\n");
+ };
+ printf ("\n");
+ printf (" DSP %08x %-20s CMD %08x DSPS %08x %s\n",
+ l(0x2c),sn(l(0x2c)),l(0x24),l(0x30), sn(l(0x30)));
+ printf (" TEMP %08x %-20s DSA %08x\n",
+ l(0x1c),sn(l(0x1c)),l(0x10));
+ printf ("\n");
+ printf (" Busstatus: ");
+ if ((reg[0x0b]>>7)&1) printf (" Req");
+ if ((reg[0x0b]>>6)&1) printf (" Ack");
+ if ((reg[0x0b]>>5)&1) printf (" Bsy");
+ if ((reg[0x0b]>>4)&1) printf (" Sel");
+ if ((reg[0x0b]>>3)&1) printf (" Atn");
+ printf (" %s\n", phasename[reg[0x0b]&7]);
+
+ printf (" Dmastatus: ");
+ if ((reg[0x0c]>>7)&1) printf (" FifoEmpty");
+ if ((reg[0x0c]>>6)&1) printf (" MasterParityError");
+ if ((reg[0x0c]>>5)&1) printf (" BusFault");
+ if ((reg[0x0c]>>4)&1) printf (" Aborted");
+ if ((reg[0x0c]>>3)&1) printf (" SingleStep");
+ if ((reg[0x0c]>>2)&1) printf (" Interrupt");
+ if ((reg[0x0c]>>0)&1) printf (" IllegalInstruction");
+ printf ("\n");
+ printf (" Intstatus: ");
+ if ((reg[0x14]>>7)&1) printf (" Abort");
+ if ((reg[0x14]>>6)&1) printf (" SoftwareReset");
+ if ((reg[0x14]>>5)&1) printf (" SignalProcess");
+ if ((reg[0x14]>>4)&1) printf (" Semaphore");
+ if ((reg[0x14]>>3)&1) printf (" Connected");
+ if ((reg[0x14]>>2)&1) printf (" IntOnTheFly");
+ if ((reg[0x14]>>1)&1) printf (" SCSI-Interrupt");
+ if ((reg[0x14]>>0)&1) printf (" DMA-Interrupt");
+ printf ("\n");
+ printf (" ScsiIstat: ");
+ if ((reg[0x42]>>7)&1) printf (" PhaseMismatch");
+ if ((reg[0x42]>>6)&1) printf (" Complete");
+ if ((reg[0x42]>>5)&1) printf (" Selected");
+ if ((reg[0x42]>>4)&1) printf (" Reselected");
+ if ((reg[0x42]>>3)&1) printf (" GrossError");
+ if ((reg[0x42]>>2)&1) printf (" UnexpectedDisconnect");
+ if ((reg[0x42]>>1)&1) printf (" ScsiReset");
+ if ((reg[0x42]>>0)&1) printf (" ParityError");
+ if ((reg[0x43]>>2)&1) printf (" SelectionTimeout");
+ if ((reg[0x43]>>1)&1) printf (" TimerExpired");
+ if ((reg[0x43]>>0)&1) printf (" HandshakeTimeout");
+ printf ("\n");
+ printf (" ID=%d DEST-ID=%d RESEL-ID=%d\n", reg[4]&7, reg[6]&7, reg[0xa]&7);
+ printf ("\n");
+}
+
+/*================================================================
+**
+**
+** Write debug info: utilities: write header.
+**
+**
+**================================================================
+*/
+
+char * debug_opt;
+
+dump_head (struct head * hp)
+{
+ dump_link (" launch", & hp->launch);
+ printf (" savep: %08x %s\n",
+ hp->savep, sn((u_long) hp->savep));
+ printf (" cp: %08x %s\n",
+ hp->cp, sn((u_long)hp->cp));
+ if (strchr (debug_opt, 'y')) {
+ printf ("\n");
+ dump_tstamp (" timestamp", &hp->stamp);
+ };
+
+ printf (" status: %x %x %x %x %x %x %x %x\n",
+ hp->status[0], hp->status[1], hp->status[2], hp->status[3],
+ hp->status[4], hp->status[5], hp->status[6], hp->status[7]);
+
+ printf ("\n");
+}
+
+/*================================================================
+**
+**
+** Write debug info: utilities: write ccb.
+**
+**
+**================================================================
+*/
+
+void dump_ccb (struct ccb * cp, u_long base)
+{
+ printf ("----------------------\n");
+ printf ("struct ccb @ %08x:\n", base);
+ printf ("----------------------\n");
+
+ dump_link (" next", &cp->jump_ccb);
+ dump_link (" call", &cp->call_tmp);
+
+ dump_head (&cp->phys.header);
+
+ if (strchr (debug_opt, 's')) {
+ dump_table(" smsg", &cp->phys.smsg, 1);
+ dump_table("smsg2", &cp->phys.smsg2, 1);
+ dump_table(" cmd", &cp->phys.cmd, 1);
+ dump_table(" data", &cp->phys.data[0],MAX_SCATTER);
+ dump_table("sense", &cp->phys.sense, 1);
+ };
+
+ if (strchr (debug_opt, 'a')) {
+ int i;
+ for (i=0; i<8; i++)
+ printf (" patch[%d]: %08x\n", i, cp->patch[i]);
+ };
+
+ if (strchr (debug_opt, 'x')) {
+ printf (" xfer: -- dump not yet implemented.\n");
+ };
+
+ if (strchr (debug_opt, 'm')) {
+ printf (" smsg:");
+ printm (cp->scsi_smsg, cp->phys.smsg.size);
+ printf ("\n");
+ printf (" smsg2:");
+ printm (cp->scsi_smsg2, cp->phys.smsg2.size);
+ printf ("\n");
+ };
+
+ printf (" magic: %x\n", cp->magic);
+ if (cp->tlimit)
+ printf (" timeout at: %s", ctime((time_t*)&cp->tlimit));
+ printf (" link_ccb: %08x\n", (u_long) cp->link_ccb);
+ printf (" next_ccb: %08x\n", (u_long) cp->next_ccb);
+ printf (" tag: %d\n", cp->tag);
+ printf ("\n");
+}
+
+/*================================================================
+**
+**
+** Write debug info: struct lcb
+**
+**
+**================================================================
+*/
+
+static void dump_lcb (u_long base)
+{
+ struct lcb l;
+ struct ccb c;
+ u_long cp,cn;
+
+ printf ("----------------------\n");
+ printf ("struct lcb @ %08x:\n", base);
+ printf ("----------------------\n");
+
+ if (!KVM_READ (
+ base,
+ &l,
+ sizeof (struct lcb))) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ };
+ printf (" reqccbs: %d\n", l.reqccbs);
+ printf (" actccbs: %d\n", l.actccbs);
+ printf (" reqlink: %d\n", l.reqlink);
+ printf (" actlink: %d\n", l.actlink);
+ printf (" usetags: %d\n", l.usetags);
+ dump_link (" jump_lcb", &l.jump_lcb);
+ dump_link (" call_tag", &l.call_tag);
+ dump_link (" jump_ccb", &l.jump_ccb);
+ printf ("\n");
+ cp = (u_long) l.next_ccb;
+ cn = 0;
+ while (cp) {
+ cn++;
+ printf ("ccb #%d:\n", cn);
+ if (!KVM_READ (
+ cp,
+ &c,
+ sizeof (struct ccb))) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ };
+ dump_ccb (&c, cp);
+ cp= (u_long) c.next_ccb;
+ };
+}
+
+/*================================================================
+**
+**
+** Write debug info: struct tcb
+**
+**
+**================================================================
+*/
+
+static void dump_tip (struct tcb * tip)
+{
+ int i;
+ u_long lp;
+
+ printf ("----------------------\n");
+ printf ("struct tcb:\n");
+ printf ("----------------------\n");
+
+ printf (" transfers:%10d.\n", tip->transfers);
+ printf (" bytes:%10d.\n", tip->bytes );
+ printf (" user limits: usrsync=%d usrwide=%d usrtags=%d.\n",
+ tip->usrsync, tip->usrwide, tip->usrtags);
+ printf (" sync: minsync=%d, maxoffs=%d, period=%d ns, sval=%x.\n",
+ tip->minsync, tip->maxoffs, tip->period, tip->sval);
+ printf (" wide: widedone=%d, wval=%x.\n",
+ tip->widedone, tip->wval);
+
+ printf (" hold_cp: %x\n", tip->hold_cp);
+ dump_link (" jump_tcb", &tip->jump_tcb);
+ dump_link (" call_lun", &tip->call_lun);
+ dump_link (" jump_lcb", &tip->jump_lcb);
+ if (tip->hold_cp) printf (" hold_cp: @ %x\n", tip->hold_cp);
+ printf ("\n");
+
+ if (strchr (debug_opt, 'l')) {
+ for (i=0;i<MAX_LUN;i++) {
+ lp= (u_long) tip->lp[i];
+ printf ("logic unit #%d:\n", i);
+ if (lp) dump_lcb (lp);
+ };
+ }
+}
+
+/*================================================================
+**
+**
+** Write debug info: struct ncb
+**
+**
+**================================================================
+*/
+
+
+static void dump_ncr (void)
+{
+ u_long tp;
+ int i;
+
+ printf ("----------------------\n");
+ printf ("struct ncb @ %x:\n", ncr_base);
+ printf ("----------------------\n");
+
+ dump_link (" jump_tcb", &ncr.jump_tcb);
+ printf (" register: @ %x (p=%x)\n", ncr.vaddr, ncr.paddr);
+
+ if (strchr (debug_opt, 'r')) {
+ struct ncr_reg reg;
+
+ if (!KVM_READ (
+ ncr.vaddr,
+ &reg,
+ sizeof (reg))) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ };
+
+ printf ("\n");
+ dump_reg (&reg);
+ };
+
+ printf (" script: @ %x (p=%x)\n", ncr.script, ncr.p_script);
+
+ printf ("hostscsiaddr: %d\n", ncr.myaddr);
+ printf (" ns_async: %d ns\n", ncr.ns_async);
+ printf (" ns_sync : %d ns\n", ncr.ns_sync);
+ printf (" scntl3: 0x%02x\n", ncr.rv_scntl3);
+ printf ("\n");
+
+ /* sc_link not dumped */
+
+ if (strchr (debug_opt, 'u')) {
+ printf (" usercmd: cmd=%x data=%x target=%x lun=%x\n",
+ ncr.user.cmd,
+ ncr.user.data,
+ ncr.user.target,
+ ncr.user.lun);
+ };
+
+ printf (" actccbs: %d\n", ncr.actccbs);
+
+ if (strchr (debug_opt, 'q')) {
+
+ u_long startpos;
+
+ if (!KVM_READ (
+ ((u_long)ncr.script
+ +offsetof(struct script, startpos)),
+ &startpos,
+ sizeof (startpos))) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ };
+
+ printf (" startpos: %x\n", startpos);
+ printf (" slot: %d\n", (startpos-
+ (ncr.p_script+offsetof(struct script, tryloop)))/20);
+ printf (" squeuput: %d\n", ncr.squeueput);
+ for (i=0; i<MAX_START; i++)
+ printf ("%12d: %08x %s\n", i,
+ ncr.squeue[i], sn(ncr.squeue[i]));
+
+ printf ("\n");
+ };
+
+ printf (" ticks: %d ms\n", ncr.ticks * 10);
+ printf (" heartbeat: %s", ctime ((time_t*)&ncr.heartbeat));
+ printf (" lasttime: %s", ctime ((time_t*)&ncr.lasttime));
+#ifndef __NetBSD__
+ printf ("imask/mcount: %x / %d\n", ncr.imask, ncr.mcount);
+#endif
+ printf ("\n");
+
+ if (strchr (debug_opt, 'd') && ncr.regtime.tv_sec) {
+ printf (" regdump: %s", ctime (&ncr.regtime.tv_sec));
+ dump_reg (&ncr.regdump);
+ };
+
+ if (strchr (debug_opt, 'p')) {
+ printf ("\n");
+ dump_profile (" profile", &ncr.profile);
+ };
+
+ if (strchr (debug_opt, 'h')) {
+ printf ("\n");
+ dump_head ( &ncr.header);
+ };
+
+ if (strchr (debug_opt, 'c')) {
+ dump_ccb (&ncr.ccb, ncr_base + offsetof (struct ncb, ccb));
+ };
+
+ if (strchr (debug_opt, 'm')) {
+ printf (" msgout:"); printm (ncr.msgout,0); printf ("\n");
+ printf (" msg in:"); printm (ncr.msgin,0); printf ("\n");
+ printf ("\n");
+ };
+
+ if (strchr (debug_opt, 't')) {
+ struct tcb * tip;
+ for (i=0;i<MAX_TARGET;i++) {
+ tip = &ncr.target[i];
+ if (!tip->jump_tcb.l_cmd) continue;
+ printf ("target #%d:\n", i);
+ dump_tip (tip);
+ }
+ }
+}
+
+/*================================================================
+**
+**
+** D O _ D E B U G
+**
+**
+**================================================================
+*/
+
+
+do_debug(char * arg)
+{
+ open_kvm(O_RDONLY);
+ debug_opt = arg;
+ if (strchr (debug_opt, '?')) printf (
+"'?': list debug options [sic].\n"
+"'a': show patchfields in ccbs (requires c).\n"
+"'c': show ccbs.\n"
+"'d': show register dump.\n"
+"'h': show header information.\n"
+"'m': show message buffers.\n"
+"'n': show ncr main control block.\n"
+"'p': show profiling information.\n"
+"'q': show start queue.\n"
+"'r': show registers (*DANGEROUS*).\n"
+"'s': show scatter/gather info.\n"
+"'t': show target control blocks.\n"
+"'u': show user cmd field.\n"
+"'x': show generic xfer structure.\n"
+"'y': show timestamps.\n"
+"\n"
+ );
+
+ if (strchr (debug_opt, 'n')) dump_ncr ();
+ if (strchr (debug_opt, 'r')) {
+ struct ncr_reg reg;
+ if (!KVM_READ (
+ ncr.vaddr,
+ &reg,
+ sizeof (reg))) {
+ fprintf (stderr, "%s: bad kvm read.\n", prog);
+ exit (1);
+ };
+ dump_reg (&reg);
+ };
+}
+
+
+/*================================================================
+**
+**
+** Main function
+**
+**
+**================================================================
+*/
+
+void main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern char *optarg;
+ extern int optind;
+ int usage=0;
+ char * charp;
+ int ch, getopt(),atoi();
+ int i,step;
+
+ prog = *argv;
+ while ((ch = getopt(argc, argv, "M:N:u:f:t:l:p:s:k:d:vwhin:?")) != -1)
+ switch((char)ch) {
+ case 'M':
+ if (kvm_isopen) {
+ fprintf (stderr,
+ "%s: -M: kernel file already open.\n",
+ prog);
+ exit (1);
+ };
+ kmemf = optarg;
+ break;
+ case 'N':
+ if (kvm_isopen) {
+ fprintf (stderr,
+ "%s: -N: symbol table already open.\n",
+ prog);
+ exit (1);
+ };
+ vmunix = optarg;
+ break;
+ case 'f':
+ fprintf (stderr,
+ "%s: -f: option not yet implemented.\n",
+ prog);
+ exit (1);
+
+ case 'u':
+ i = strtoul (optarg, &charp, 0);
+ if (!*optarg || *charp || (i<0)) {
+ fprintf (stderr,
+ "%s: bad unit number \"%s\".\n",
+ prog, optarg);
+ exit (1);
+ }
+ ncr_unit = i;
+ break;
+ case 't':
+ i = strtoul (optarg, &charp, 0);
+ if (!*optarg || *charp || (i<0) || (i>=MAX_TARGET)) {
+ fprintf (stderr,
+ "%s: bad target number \"%s\" (valid range: 0-%d).\n",
+ prog, optarg, MAX_TARGET-1);
+ exit (1);
+ }
+ target_mask |= 1ul << i;
+ break;
+ case 'n':
+ open_kvm(O_RDONLY);
+ i = strtoul (optarg, &charp, 0);
+ printf ("addr %d (0x%x) has label %s.\n",
+ i,i,sn(i));
+ break;
+ case 'l':
+ i = strtoul (optarg, &charp, 0);
+ if (!*optarg || *charp || (i<0) || (i>=MAX_LUN)) {
+ fprintf (stderr,
+ "%s: bad logic unit number \"%s\" (valid range: 0-%d).\n",
+ prog, optarg, MAX_LUN);
+ exit (1);
+ }
+ global_lun_mask |= 1ul << i;
+ break;
+ case 'p':
+ i = strtoul (optarg, &charp, 0);
+ if (!*optarg || *charp || (i<1) || (i>60)) {
+ fprintf (stderr,
+ "%s: bad interval \"%s\".\n",
+ prog, optarg);
+ exit (1);
+ }
+ interval = i;
+ do_profile();
+ break;
+
+ case 'w':
+ wizard=1;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'i':
+ do_info();
+ break;
+
+ case 's':
+ do_set(optarg);
+ break;
+ case 'd':
+ do_debug(optarg);
+ break;
+ case 'k':
+ do_kill(optarg);
+ break;
+ case 'h':
+ case '?':
+ usage++;
+ break;
+ default:(void)fprintf(stderr,
+ "%s: illegal option \"%c\".\n", prog, ch);
+ usage++;
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc) printf ("%s: rest of line starting with \"%s\" ignored.\n",
+ prog, *argv);
+
+ if (verbose&&!kvm_isopen) usage++;
+ if (usage) {
+ fprintf (stderr,
+ "Usage:\n"
+ "\n"
+ "%s [-M$] [-N$] {-f$} {-t#} {-l#} [-hivw?] [-d$] [-s$] [-k] [[-p] <time>]\n"
+ "\n"
+ "-t <#> select target number\n"
+ "-l <#> select lun number\n"
+ "-i get info\n"
+ "-v verbose\n"
+ "-p <seconds> performance data\n"
+ "\n"
+ "Wizards only (proceed on your own risk):\n"
+ "-n <#> get the name for address #\n"
+ "-w wizard mode\n"
+ "-d <options> debug info\n"
+ "-d? list debug options\n"
+ "-s <param=value> set parameter\n"
+ "-s? list parameters\n"
+ "-k <torture> torture driver by simulating errors\n"
+ "-k? list tortures\n"
+ "-M <kernelimage> (default: %s)\n"
+ "-N <symboltable> (default: %s)\n"
+ , prog, _PATH_KMEM, _PATH_UNIX);
+ if (verbose) fprintf (stderr, ident);
+ exit (1);
+ }
+
+ if (!kvm_isopen) {
+ do_info();
+ do_profile();
+ };
+ exit (0);
+}
OpenPOWER on IntegriCloud