Subject: kern/1958: MI SCSI autoconfiguration messages zany and unclear.
To: None <gnats-bugs@gnats.netbsd.org>
From: Chris G. Demetriou <cgd@NetBSD.ORG>
List: netbsd-bugs
Date: 01/18/1996 21:20:04
>Number:         1958
>Category:       kern
>Synopsis:       MI SCSI autoconfig messages aren't of the standard form.
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Thu Jan 18 21:50:03 1996
>Last-Modified:
>Originator:     Chris G. Demetriou
>Organization:
Kernel Hackers 'r' Us
>Release:        NetBSD-current, January 18, 1996
>Environment:
System: NetBSD sun-lamp.pc.cs.cmu.edu 1.1A NetBSD 1.1A (SUN_LAMP) #34: Thu Jan 18 20:53:30 EST 1996 cgd@sun-lamp.pc.cs.cmu.edu:/usr/src/sys/arch/i386/compile/SUN_LAMP i386


>Description:
	NetBSD's MI SCSI autoconfiguration messages are zany, and less
	clear than they could be.  This is because they don't follow the
	same form as other autoconfiguration messages.

	"normal" autoconfig messages take the form:

		B at A [attach info][: device info]
		C at B [attach info][: device info]
		D at C [attach info][: device info]
		E at C [attach info][: device info]

	e.g.:

		isa0 (root)
		ast0 at isa0 port 0x1a0-0x1bf irq 3
		com0 at ast0 slave 0: ns16550a, working fifo
		com1 at ast0 slave 1: ns16550a, working fifo
		com2 at ast0 slave 2: ns16550a, working fifo
		com3 at ast0 slave 3: ns16550a, working fifo

	But this is not what the MI SCSI autoconfiguration messages
	look like!

	They look like:

		B at A
		A [attach info][: device info]
		C at B[: device info]

	e.g.:

		scsibus0 at bt0
		bt0 targ 0 lun 0: <QUANTUM, PD1225S, 3110> SCSI2 0/direct fixed
		sd0 at scsibus0: 1169MB, 2448 cyl, 14 head, 69 sec, 512 bytes/sec

	There is no direct connection shown as to where sd0 is on scsibus0
	(the only connection indicated is done so by the position of
	the lines in autoconfig output).

	It's also not 'standard form;' if all devices output information in
	the standard:
		B at A [attach info][:device info]
	form, then one could write a program to generate part of a kernel
	configuration from the dmesg output.  Given the way the MI SCSI
	code currently does autoconfig output, it would have to be a
	special case.

>How-To-Repeat:
	Look at 'dmesg' output, note that the MI SCSI autoconfiguration
	messages look 'weird' compared to other autoconfig messages.

>Fix:
	Enclosed below is a patch that fixes this.  For the example
	above, the autoconfiguration output ends up looking like:

	scsibus0 at bt0
	sd0 at scsibus0 targ 0 lun 0: <QUANTUM, PD1225S, 3110> SCSI2 0/direct fixed
	sd0: 1169MB, 2448 cyl, 14 head, 69 sec, 512 bytes/sec

	This directly indicates where sd0 is attached, and prints
	device-dependent autoconfiguration information on a seperate
	informational line.

	Devices not recognized by the kernel are noted like:

	scsibus0 targ 6 lun 0: <WangDAT, Model 3200, 01.9> SCSI2 1/sequential removable not configured

	There are other ways to get the same information, properly formatted
	out to the user, but i picked this way because it best fit
	with the existing code, and becasue it involved no redundancy in
	the autoconfiguration output.

Index: ch.c
===================================================================
RCS file: /a/cvsroot/src/sys/scsi/ch.c,v
retrieving revision 1.14
diff -c -r1.14 ch.c
*** ch.c	1995/01/16 21:31:38	1.14
--- ch.c	1996/01/19 02:06:59
***************
*** 137,146 ****
  	 * the drive. We cannot use interrupts yet, so the
  	 * request must specify this.
  	 */
  	if (ch_mode_sense(ch, SCSI_AUTOCONF) != 0)
! 		printf(": offline\n");
  	else
! 		printf(": %d slot(s), %d drive(s), %d arm(s), %d i/e-slot(s)\n",
  		    ch->slots, ch->drives, ch->chms, ch->imexs);
  }
  
--- 137,148 ----
  	 * the drive. We cannot use interrupts yet, so the
  	 * request must specify this.
  	 */
+ 	printf("\n");
+ 	printf("%s: ", ch->sc_dev.dv_xname);
  	if (ch_mode_sense(ch, SCSI_AUTOCONF) != 0)
! 		printf("offline\n");
  	else
! 		printf("%d slot(s), %d drive(s), %d arm(s), %d i/e-slot(s)\n",
  		    ch->slots, ch->drives, ch->chms, ch->imexs);
  }
  
Index: scsiconf.c
===================================================================
RCS file: /a/cvsroot/src/sys/scsi/scsiconf.c,v
retrieving revision 1.47
diff -c -r1.47 scsiconf.c
*** scsiconf.c	1996/01/12 11:32:37	1.47
--- scsiconf.c	1996/01/19 02:06:59
***************
*** 91,96 ****
--- 91,98 ----
  	sizeof(struct scsibus_softc)
  };
  
+ int scsibusprint __P((void *, char *));
+ 
  int
  scsibusmatch(parent, match, aux)
          struct device *parent;
***************
*** 360,365 ****
--- 362,475 ----
  };
  
  /*
+  * Print out autoconfiguration information for a subdevice.
+  *
+  * This is a slight abuse of 'standard' autoconfiguration semantics,
+  * because 'print' functions don't normally print the colon and
+  * device information.  However, in this case that's better than
+  * either printing redundant information before the attach message,
+  * or having the device driver call a special function to print out
+  * the standard device information.
+  */
+ int
+ scsibusprint(aux, pnp)
+ 	void *aux;
+ 	char *pnp;
+ {
+ 	struct scsibus_attach_args *sa = aux;
+ 	struct scsi_inquiry_data *inqbuf;
+ 	u_int8_t type;
+ 	boolean removable;
+ 	char *dtype, *qtype;
+ 	char vendor[33], product[65], revision[17];
+ 	int target, lun;
+ 
+ 	if (pnp != NULL)
+ 		printf("%s", pnp);
+ 
+ 	inqbuf = sa->sa_inqbuf;
+ 
+         target = sa->sa_sc_link->target;
+         lun = sa->sa_sc_link->lun;
+ 
+         type = inqbuf->device & SID_TYPE;
+         removable = inqbuf->dev_qual2 & SID_REMOVABLE ? 1 : 0;
+ 
+ 	/*
+ 	 * Figure out basic device type and qualifier.
+ 	 */
+ 	dtype = 0;
+ 	switch (inqbuf->device & SID_QUAL) {
+ 	case SID_QUAL_LU_OK:
+ 		qtype = "";
+ 		break;
+ 
+ 	case SID_QUAL_LU_OFFLINE:
+ 		qtype = " offline";
+ 		break;
+ 
+ 	case SID_QUAL_RSVD:
+ 	case SID_QUAL_BAD_LU:
+ 		panic("scsibusprint: impossible qualifier");
+ 
+ 	default:
+ 		qtype = "";
+ 		dtype = "vendor-unique";
+ 		break;
+ 	}
+ 	if (dtype == 0) {
+ 		switch (type) {
+ 		case T_DIRECT:
+ 			dtype = "direct";
+ 			break;
+ 		case T_SEQUENTIAL:
+ 			dtype = "sequential";
+ 			break;
+ 		case T_PRINTER:
+ 			dtype = "printer";
+ 			break;
+ 		case T_PROCESSOR:
+ 			dtype = "processor";
+ 			break;
+ 		case T_CDROM:
+ 			dtype = "cdrom";
+ 			break;
+ 		case T_WORM:
+ 			dtype = "worm";
+ 			break;
+ 		case T_SCANNER:
+ 			dtype = "scanner";
+ 			break;
+ 		case T_OPTICAL:
+ 			dtype = "optical";
+ 			break;
+ 		case T_CHANGER:
+ 			dtype = "changer";
+ 			break;
+ 		case T_COMM:
+ 			dtype = "communication";
+ 			break;
+ 		case T_NODEVICE:
+ 			panic("scsibusprint: impossible device type");
+ 		default:
+ 			dtype = "unknown";
+ 			break;
+ 		}
+ 	}
+ 
+         scsi_strvis(vendor, inqbuf->vendor, 8);
+         scsi_strvis(product, inqbuf->product, 16);
+         scsi_strvis(revision, inqbuf->revision, 4);
+ 
+         printf(" targ %d lun %d: <%s, %s, %s> SCSI%d %d/%s %s%s",
+             target, lun, vendor, product, revision,
+             inqbuf->version & SID_ANSII, type, dtype,
+             removable ? "removable" : "fixed", qtype);
+ 
+ 	return (UNCONF);
+ }
+ 
+ /*
   * given a target and lu, ask the device what
   * it is, and find the correct driver table
   * entry.
***************
*** 372,382 ****
  	struct scsi_link *sc_link;
  	static struct scsi_inquiry_data inqbuf;
  	struct scsi_quirk_inquiry_pattern *finger;
! 	int priority;
! 	u_int8_t type;
! 	boolean removable;
! 	char *dtype, *qtype;
! 	char vendor[33], product[65], revision[17];
  	struct scsibus_attach_args sa;
  	struct cfdata *cf;
  
--- 482,488 ----
  	struct scsi_link *sc_link;
  	static struct scsi_inquiry_data inqbuf;
  	struct scsi_quirk_inquiry_pattern *finger;
! 	int checkdtype, priority;
  	struct scsibus_attach_args sa;
  	struct cfdata *cf;
  
***************
*** 436,459 ****
  	/*
  	 * note what BASIC type of device it is
  	 */
! 	type = inqbuf.device & SID_TYPE;
! 	removable = inqbuf.dev_qual2 & SID_REMOVABLE ? 1 : 0;
! 
! 	if (removable)
  		sc_link->flags |= SDEV_REMOVABLE;
  
  	/*
  	 * Any device qualifier that has the top bit set (qualifier&4 != 0)
  	 * is vendor specific and won't match in this switch.
  	 */
! 	dtype = 0;
  	switch (inqbuf.device & SID_QUAL) {
  	case SID_QUAL_LU_OK:
- 		qtype = "";
- 		break;
- 
  	case SID_QUAL_LU_OFFLINE:
! 		qtype = " offline";
  		break;
  
  	case SID_QUAL_RSVD:
--- 542,560 ----
  	/*
  	 * note what BASIC type of device it is
  	 */
! 	if ((inqbuf.dev_qual2 & SID_REMOVABLE) != 0)
  		sc_link->flags |= SDEV_REMOVABLE;
  
  	/*
  	 * Any device qualifier that has the top bit set (qualifier&4 != 0)
  	 * is vendor specific and won't match in this switch.
+ 	 * All we do here is throw out bad/negative responses.
  	 */
! 	checkdtype = 0;
  	switch (inqbuf.device & SID_QUAL) {
  	case SID_QUAL_LU_OK:
  	case SID_QUAL_LU_OFFLINE:
! 		checkdtype = 1;
  		break;
  
  	case SID_QUAL_RSVD:
***************
*** 461,528 ****
  		goto bad;
  
  	default:
- 		qtype = "";
- 		dtype = "vendor-unique";
  		break;
  	}
! 	if (dtype == 0) {
! 		switch (type) {
  		case T_DIRECT:
- 			dtype = "direct";
- 			break;
  		case T_SEQUENTIAL:
- 			dtype = "sequential";
- 			break;
  		case T_PRINTER:
- 			dtype = "printer";
- 			break;
  		case T_PROCESSOR:
- 			dtype = "processor";
- 			break;
  		case T_CDROM:
- 			dtype = "cdrom";
- 			break;
  		case T_WORM:
- 			dtype = "worm";
- 			break;
  		case T_SCANNER:
- 			dtype = "scanner";
- 			break;
  		case T_OPTICAL:
- 			dtype = "optical";
- 			break;
  		case T_CHANGER:
- 			dtype = "changer";
- 			break;
  		case T_COMM:
! 			dtype = "communication";
  			break;
  		case T_NODEVICE:
  			goto bad;
- 		default:
- 			dtype = "unknown";
- 			break;
  		}
  	}
  
- 	scsi_strvis(vendor, inqbuf.vendor, 8);
- 	scsi_strvis(product, inqbuf.product, 16);
- 	scsi_strvis(revision, inqbuf.revision, 4);
- 
- 	printf("%s targ %d lun %d: <%s, %s, %s> SCSI%d %d/%s %s%s\n",
- 	    ((struct device *)sc_link->adapter_softc)->dv_xname,
- 	    target, lun, vendor, product, revision,
- 	    inqbuf.version & SID_ANSII, type, dtype,
- 	    removable ? "removable" : "fixed", qtype);
- 
  	sa.sa_sc_link = sc_link;
  	sa.sa_inqbuf = &inqbuf;
  
  	if ((cf = config_search(scsibussubmatch, (struct device *)scsi, &sa)) != 0) {
  		scsi->sc_link[target][lun] = sc_link;
! 		config_attach((struct device *)scsi, cf, &sa, NULL);
! 	} else
  		goto bad;
  
  	return;
  
--- 562,599 ----
  		goto bad;
  
  	default:
  		break;
  	}
! 	if (checkdtype) {
! 		switch (inqbuf.device & SID_TYPE) {
  		case T_DIRECT:
  		case T_SEQUENTIAL:
  		case T_PRINTER:
  		case T_PROCESSOR:
  		case T_CDROM:
  		case T_WORM:
  		case T_SCANNER:
  		case T_OPTICAL:
  		case T_CHANGER:
  		case T_COMM:
! 		default:
  			break;
  		case T_NODEVICE:
  			goto bad;
  		}
  	}
  
  	sa.sa_sc_link = sc_link;
  	sa.sa_inqbuf = &inqbuf;
  
  	if ((cf = config_search(scsibussubmatch, (struct device *)scsi, &sa)) != 0) {
  		scsi->sc_link[target][lun] = sc_link;
! 		config_attach((struct device *)scsi, cf, &sa, scsibusprint);
! 	} else {
! 		scsibusprint(&sa, scsi->sc_dev.dv_xname);
! 		printf(" not configured\n");
  		goto bad;
+ 	}
  
  	return;
  
Index: sd.c
===================================================================
RCS file: /a/cvsroot/src/sys/scsi/sd.c,v
retrieving revision 1.85
diff -c -r1.85 sd.c
*** sd.c	1996/01/12 22:43:33	1.85
--- sd.c	1996/01/19 02:07:04
***************
*** 193,204 ****
  	 * the drive. We cannot use interrupts yet, so the
  	 * request must specify this.
  	 */
  	if (scsi_start(sd->sc_link, SSS_START,
  	    SCSI_AUTOCONF | SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE | SCSI_SILENT) ||
  	    sd_get_parms(sd, SCSI_AUTOCONF) != 0)
! 		printf(": drive offline\n");
  	else
! 	        printf(": %dMB, %d cyl, %d head, %d sec, %d bytes/sec\n",
  		    dp->disksize / (1048576 / dp->blksize), dp->cyls,
  		    dp->heads, dp->sectors, dp->blksize);
  }
--- 193,206 ----
  	 * the drive. We cannot use interrupts yet, so the
  	 * request must specify this.
  	 */
+ 	printf("\n");
+ 	printf("%s: ", sd->sc_dev.dv_xname);
  	if (scsi_start(sd->sc_link, SSS_START,
  	    SCSI_AUTOCONF | SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE | SCSI_SILENT) ||
  	    sd_get_parms(sd, SCSI_AUTOCONF) != 0)
! 		printf("drive offline\n");
  	else
! 	        printf("%dMB, %d cyl, %d head, %d sec, %d bytes/sec\n",
  		    dp->disksize / (1048576 / dp->blksize), dp->cyls,
  		    dp->heads, dp->sectors, dp->blksize);
  }
Index: st.c
===================================================================
RCS file: /a/cvsroot/src/sys/scsi/st.c,v
retrieving revision 1.57
diff -c -r1.57 st.c
*** st.c	1996/01/11 03:36:38	1.57
--- st.c	1996/01/19 02:07:08
***************
*** 359,365 ****
  	 * the drive. We cannot use interrupts yet, so the
  	 * request must specify this.
  	 */
! 	printf(": %s", st->quirkdata ? "rogue, " : "");
  	if (scsi_test_unit_ready(sc_link,
  	    SCSI_AUTOCONF | SCSI_SILENT | SCSI_IGNORE_MEDIA_CHANGE) ||
  	    st_mode_sense(st,
--- 359,366 ----
  	 * the drive. We cannot use interrupts yet, so the
  	 * request must specify this.
  	 */
! 	printf("\n");
! 	printf("%s: %s", st->sc_dev.dv_xname, st->quirkdata ? "rogue, " : "");
  	if (scsi_test_unit_ready(sc_link,
  	    SCSI_AUTOCONF | SCSI_SILENT | SCSI_IGNORE_MEDIA_CHANGE) ||
  	    st_mode_sense(st,
Index: uk.c
===================================================================
RCS file: /a/cvsroot/src/sys/scsi/uk.c,v
retrieving revision 1.13
diff -c -r1.13 uk.c
*** uk.c	1995/03/24 20:17:15	1.13
--- uk.c	1996/01/19 02:07:09
***************
*** 100,106 ****
  	sc_link->device_softc = uk;
  	sc_link->openings = 1;
  
! 	printf(": unknown device\n");
  }
  
  /*
--- 100,107 ----
  	sc_link->device_softc = uk;
  	sc_link->openings = 1;
  
! 	printf("\n");
! 	printf("%s: unknown device\n", uk->sc_dev.dv_xname);
  }
  
  /*
>Audit-Trail:
>Unformatted: