Subject: LUNS in NetBSD SCSI Subsystem/SCSI Configuration
To: None <tech-kern@netbsd.org>
From: Matthew Jacob <mjacob@feral.com>
List: tech-kern
Date: 12/01/1998 19:02:30
Currently the SCSI subsystem assumes 8 luns. Most newer HBAs support 32
luns, and even more important, the SCSI-3 specification supports
hierarchical luns and they are starting to be implemented- this is a group
of 4 16 bit 'lun' selectors (I doubt anything other then a 1st level 16
bit lun will be implemented for quite some time- and I'm not proposing
support for the fullblown luns but...).

So, the 'moreluns' qualifier and the search path in the internal
structures really isn't up to this. It also currently breaks on the
current FC SCSI busses when you have a 'target' (FC Loop ID) > 31 anyhow.

Below are some patches (relative to sys/dev/scsi) that fix this as well as
address the issue of being able to control the number of luns available on
a per hba basis. The latter case allows me, for instance, to support 32
luns per target for the Qlogic 1040 and then support the 16 luns per
target for the Qlogic 2100 and then decide I only want to support two luns
per target for the Advansys (e.g.).

The change is slightly ugly in that in order to not have to touch any HBA
drivers, I've added a nluns tag to the scsipi_link structure. This does
not have the same semantics as the max_target tag in the same structure
because I wanted a zero to mean the old default 8 luns per target
assumption.

I didn't put a lot of time into this- but it quickly solved the problem I
was running into where a disk at target 113 (Fibre Channel) which actually
is a soft target with multiple luns wasn't getting probed at other than
lun zero, and it leaves open room for changing the number luns supported
in my next Qlogic HBA drop (sometime in the next couple weeks).

Thoughts? Comments? Review, someone?

-matt

Index: scsiconf.c
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/scsiconf.c,v
retrieving revision 1.118
diff -c -r1.118 scsiconf.c
*** scsiconf.c	1998/11/26 13:39:14	1.118
--- scsiconf.c	1998/12/02 03:00:48
***************
*** 87,93 ****
  /*
   * Declarations
   */
! void scsi_probedev __P((struct scsibus_softc *, int, int));
  int scsi_probe_bus __P((int bus, int target, int lun));
  
  struct scsipi_device probe_switch = {
--- 87,93 ----
  /*
   * Declarations
   */
! int scsi_probedev __P((struct scsibus_softc *, int, int));
  int scsi_probe_bus __P((int bus, int target, int lun));
  
  struct scsipi_device probe_switch = {
***************
*** 173,179 ****
  
  	sb->adapter_link = sc_link_proto;
  	sb->sc_maxtarget = sc_link_proto->scsipi_scsi.max_target;
! 	printf(": %d targets\n", sb->sc_maxtarget + 1);
  
  	/* Initialize shared data. */
  	scsipi_init();
--- 173,183 ----
  
  	sb->adapter_link = sc_link_proto;
  	sb->sc_maxtarget = sc_link_proto->scsipi_scsi.max_target;
! 	sb->sc_maxlun = sc_link_proto->scsipi_scsi.nluns - 1;
! 	if (sb->sc_maxlun < 0)
! 		sb->sc_maxlun = 7;	/* 8 LUNS */
! 	printf(": %d targets, %d luns per target\n",
! 	    sb->sc_maxtarget + 1, sb->sc_maxlun + 1);
  
  	/* Initialize shared data. */
  	scsipi_init();
***************
*** 184,190 ****
  	if (sb->sc_link == NULL)
  		panic("scsibusattach: can't allocate target links");
  
! 	nbytes = 8 * sizeof(struct scsipi_link *);
  	for (i = 0; i <= sb->sc_maxtarget; i++) {
  		sb->sc_link[i] = (struct scsipi_link **)malloc(nbytes,
  		    M_DEVBUF, M_NOWAIT);
--- 188,194 ----
  	if (sb->sc_link == NULL)
  		panic("scsibusattach: can't allocate target links");
  
! 	nbytes = (((int) sb->sc_maxlun) + 1) * sizeof(struct scsipi_link *);
  	for (i = 0; i <= sb->sc_maxtarget; i++) {
  		sb->sc_link[i] = (struct scsipi_link **)malloc(nbytes,
  		    M_DEVBUF, M_NOWAIT);
***************
*** 273,282 ****
  	}
  
  	if (lun == -1) {
! 		maxlun = 7;
  		minlun = 0;
  	} else {
! 		if (lun < 0 || lun > 7)
  			return (EINVAL);
  		maxlun = minlun = lun;
  	}
--- 277,286 ----
  	}
  
  	if (lun == -1) {
! 		maxlun = scsi->sc_maxlun;
  		minlun = 0;
  	} else {
! 		if (lun < 0 || lun > scsi->sc_maxlun)
  			return (EINVAL);
  		maxlun = minlun = lun;
  	}
***************
*** 290,298 ****
  			/*
  			 * See if there's a device present, and configure it.
  			 */
! 			scsi_probedev(scsi, target, lun);
! 			if ((scsi->moreluns & (1 << target)) == 0)
  				break;
  			/* otherwise something says we should look further */
  		}
  	}
--- 294,302 ----
  			/*
  			 * See if there's a device present, and configure it.
  			 */
! 			if (scsi_probedev(scsi, target, lun) == 0) {
  				break;
+ 			}
  			/* otherwise something says we should look further */
  		}
  	}
***************
*** 565,570 ****
--- 569,577 ----
  
  	{{T_CHANGER, T_REMOV,
  	 "SONY    ", "CDL1100         ", ""},     SDEV_NOLUNS},
+ 
+ 	{{T_ENCLOSURE, T_FIXED,
+ 	 "SUN     ", "SENA            ", "1.07"}, SDEV_NOLUNS},
  };
  
  /*
***************
*** 572,578 ****
   * it is, and find the correct driver table
   * entry.
   */
! void
  scsi_probedev(scsi, target, lun)
  	struct scsibus_softc *scsi;
  	int target, lun;
--- 579,585 ----
   * it is, and find the correct driver table
   * entry.
   */
! int
  scsi_probedev(scsi, target, lun)
  	struct scsibus_softc *scsi;
  	int target, lun;
***************
*** 580,592 ****
  	struct scsipi_link *sc_link;
  	static struct scsipi_inquiry_data inqbuf;
  	struct scsi_quirk_inquiry_pattern *finger;
! 	int checkdtype, priority;
  	struct scsipibus_attach_args sa;
  	struct cfdata *cf;
  
  	/* Skip this slot if it is already attached. */
  	if (scsi->sc_link[target][lun] != NULL)
! 		return;
  
  	sc_link = malloc(sizeof(*sc_link), M_DEVBUF, M_NOWAIT);
  	*sc_link = *scsi->adapter_link;
--- 587,607 ----
  	struct scsipi_link *sc_link;
  	static struct scsipi_inquiry_data inqbuf;
  	struct scsi_quirk_inquiry_pattern *finger;
! 	int checkdtype, priority, docontinue;
  	struct scsipibus_attach_args sa;
  	struct cfdata *cf;
  
+ 	/*
+ 	 * Assume no more luns to search after this one.
+ 	 * If we successfully get Inquiry data and after
+ 	 * merging quirks we find we can probe for more
+ 	 * luns, we will.
+ 	 */
+ 	docontinue = 0;
+ 
  	/* Skip this slot if it is already attached. */
  	if (scsi->sc_link[target][lun] != NULL)
! 		return (docontinue);
  
  	sc_link = malloc(sizeof(*sc_link), M_DEVBUF, M_NOWAIT);
  	*sc_link = *scsi->adapter_link;
***************
*** 662,668 ****
  	sc_link->scsipi_scsi.scsi_version = inqbuf.version;
  
  	if ((sc_link->quirks & SDEV_NOLUNS) == 0)
! 		scsi->moreluns |= (1 << target);
  
  	/*
  	 * note what BASIC type of device it is
--- 677,683 ----
  	sc_link->scsipi_scsi.scsi_version = inqbuf.version;
  
  	if ((sc_link->quirks & SDEV_NOLUNS) == 0)
! 		docontinue = 1;
  
  	/*
  	 * note what BASIC type of device it is
***************
*** 721,731 ****
  		goto bad;
  	}
  
! 	return;
  
  bad:
  	free(sc_link, M_DEVBUF);
! 	return;
  }
  
  /****** Entry points for user control of the SCSI bus. ******/
--- 736,746 ----
  		goto bad;
  	}
  
! 	return (docontinue);
  
  bad:
  	free(sc_link, M_DEVBUF);
! 	return (docontinue);
  }
  
  /****** Entry points for user control of the SCSI bus. ******/
Index: scsiconf.h
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/scsiconf.h,v
retrieving revision 1.46
diff -c -r1.46 scsiconf.h
*** scsiconf.h	1998/11/17 14:38:42	1.46
--- scsiconf.h	1998/12/02 03:00:48
***************
*** 75,82 ****
  	struct scsipi_link *adapter_link; /* prototype supplied by adapter */
  	struct scsipi_link ***sc_link;		/* dynamically allocated */
  	int	sc_flags;
! 	int	sc_maxtarget;
! 	u_int8_t moreluns;
  };
  
  /* sc_flags */
--- 75,82 ----
  	struct scsipi_link *adapter_link; /* prototype supplied by adapter */
  	struct scsipi_link ***sc_link;		/* dynamically allocated */
  	int	sc_flags;
! 	int16_t	sc_maxtarget;
! 	int16_t	sc_maxlun;
  };
  
  /* sc_flags */
Index: scsipiconf.h
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/scsipiconf.h,v
retrieving revision 1.25
diff -c -r1.25 scsipiconf.h
*** scsipiconf.h	1998/11/19 20:08:52	1.25
--- scsipiconf.h	1998/12/02 03:00:49
***************
*** 217,224 ****
  			u_int8_t lun;		/* lun of this dev */
  			u_int8_t adapter_target;/* what are we on the scsi
  						   bus */
! 			int max_target;		/* XXX max target supported
! 						   by adapter */
  		} scsipi_scsi;
  		struct atapi_link {
  			u_int8_t drive; 	/* drive number on the bus */
--- 217,233 ----
  			u_int8_t lun;		/* lun of this dev */
  			u_int8_t adapter_target;/* what are we on the scsi
  						   bus */
! 			/*
! 			 * The semantics of these two are slightly different.
! 			 * The interests of keeping change perturbation small
! 			 * implies that this would happen. Sigh. This way
! 			 * we don't have to update all the hba drivers.
! 			 */
! 			int16_t max_target;	/* XXX max target supported
! 						   by adapter (inclusive) */
! 			int16_t nluns;		/* XXX number of luns supported
! 						   by adapter. If zero, then
! 						   SCSI-1 8 LUNS assumed */
  		} scsipi_scsi;
  		struct atapi_link {
  			u_int8_t drive; 	/* drive number on the bus */