8faab3c2e8
New version with support for the NCR 53c810 and 53c825. Support for WIDE SCSI devices.
1635 lines
38 KiB
C
1635 lines
38 KiB
C
/**************************************************************************
|
||
**
|
||
** $Id: ncrstat.c,v 2.0.0.9 94/09/11 22:12:21 wolf 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 <i386/pci/ncr.c>
|
||
|
||
/*
|
||
** used external functions
|
||
*/
|
||
|
||
#ifdef __NetBSD__
|
||
#include <kvm.h>
|
||
kvm_t *kvm;
|
||
#define KVM_NLIST(n) (kvm_nlist(kvm, (n)) >= 0)
|
||
#define KVM_READ(o, p, l) (kvm_read(kvm, (o), (p), (l)) == (l))
|
||
#else
|
||
extern int kvm_openfiles();
|
||
extern int kvm_nlist();
|
||
extern char* kvm_geterr();
|
||
extern int kvm_read();
|
||
#define KVM_NLIST(n) (kvm_nlist((n)) >= 0)
|
||
#define KVM_READ(o, p, l) (kvm_read((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 (
|
||
(void*)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 (
|
||
(void*)base,
|
||
&lcb,
|
||
sizeof (struct lcb))) {
|
||
fprintf (stderr, "%s: bad kvm read at %x.\n", prog, base);
|
||
exit (1);
|
||
};
|
||
}
|
||
|
||
read_ncr()
|
||
{
|
||
if (!KVM_READ (
|
||
(void*)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;
|
||
#ifdef __NetBSD__
|
||
char errbuf[_POSIX2_LINE_MAX];
|
||
#endif
|
||
|
||
if (kvm_isopen) return;
|
||
|
||
#ifdef __NetBSD__
|
||
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 (
|
||
(void*)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 (
|
||
(void*)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 (
|
||
(void*)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 (
|
||
(void*)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 (
|
||
(void*)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 (
|
||
(void*)(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 (
|
||
(void*)(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<=SCSI_NCR_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 (
|
||
(void*)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 (
|
||
(void*)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 (
|
||
(void*)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 (
|
||
(void*)((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 (
|
||
(void*)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);
|
||
}
|