/************************************************************************** ** ** $Id: ncrcontrol.c,v 1.12 1996/10/25 15:36:42 bde 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 #include #ifdef __NetBSD__ #include #endif #include #include #include #include #include #include #include #include /* ** 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 } }; const char *vmunix = NULL; 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) /* * Discard setgid privileges if not the running kernel so that bad * guys can't print interesting stuff from kernel memory. */ if (vmunix != NULL || kmemf != NULL) setgid(getgid()); else { #if (__FreeBSD__ >= 2) vmunix = getbootfile(); #else vmunix = _PATH_UNIX; #endif } kvm = kvm_openfiles(vmunix, kmemf, NULL, flags, errbuf); if (kvm == NULL) { fprintf(stderr, "%s: kvm_openfiles: %s\n", prog, errbuf); exit(1); } #else if (vmunix != NULL) { #if (__FreeBSD__ >= 2) vmunix = getbootfile(); #else vmunix = _PATH_UNIX; #endif } 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; tlp[l]) lun_mask |= (1<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>t)&1)) continue; tip = &ncr.target[t]; set_lun_mask(tip); if (!lun_mask) lun_mask=1; fl=1; for (l=0; l>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 ("%42s", ""); 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"); } /*================================================================ ** ** ** 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>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>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>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; 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; }; 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); }; set_target_mask(); user.target = target_mask; user.lun = lun_mask; user.data = 0; user.cmd = 0; 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)) { double 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))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;ilp[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 (wizard && 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; ijump_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 (!wizard) { fprintf (stderr, "%s: You are NOT a wizard!\n", prog); exit (2); }; 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; #ifdef OPT_F case 'f': fprintf (stderr, "%s: -f: option not yet implemented.\n", prog); exit (1); #endif 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': if(geteuid()==0) 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$] [-u] {-t#} {-l#} [-hivw?] [-d$] [-s$] [-k] [[-p]