diff options
author | se <se@FreeBSD.org> | 1994-10-12 12:02:52 +0000 |
---|---|---|
committer | se <se@FreeBSD.org> | 1994-10-12 12:02:52 +0000 |
commit | 1ce59152137cebda41511acadbda3d02a73dc3fb (patch) | |
tree | 27cda998b2b6f27a9424246832b26c0d4662d02f /usr.sbin/ncrcontrol/ncrcontrol.c | |
download | FreeBSD-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/ncrcontrol.c')
-rw-r--r-- | usr.sbin/ncrcontrol/ncrcontrol.c | 1630 |
1 files changed, 1630 insertions, 0 deletions
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, + ®, + sizeof (reg))) { + fprintf (stderr, "%s: bad kvm read.\n", prog); + exit (1); + }; + + printf ("\n"); + dump_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, + ®, + sizeof (reg))) { + fprintf (stderr, "%s: bad kvm read.\n", prog); + exit (1); + }; + dump_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); +} |