Subject: Re: old SCSI devices that don't support INQUIRY
To: Matthew Fredette , Mitch Bradley <wmb@firmworks.com>
From: Matthew Jacob <mjacob@feral.com>
List: tech-kern
Date: 09/14/2001 11:44:11
On Fri, 14 Sep 2001, Matthew Fredette wrote:

>
> > > This controller is so simple, it doesn't look at the commands you ask
> > > it to put on the wire - meaning it's not really a SASI-only or SCSI-1
> > > only controller.  I usually have more modern SCSI-2 disks and tapes
> > > hooked up and everything works fine.
> >
> > Well, disconnect/reconnect doesn't work last I checked. When I did
> > the SCSI rewrite at Sun (aeons ago) I also did unified ncr (for the
> > 5 different 5380 variants that Sun had) and the sc driver as well. I
> > found it indeed did mostly work with a base disk driver that assumed
> > CCS.
>
> Cool, finally I find someone that knows the sc board! Ya, no
> disconnect/reselect, and host can't initiate a message phase.  Can you
> clear up a parity issue?  I've heard rumblings that the sc might
> have flakey parity handling, so I run with it disabled on all devices.

You're asking me to remember stuff from 12 years ago :-)... I seem to recall
something about this, yes. Mitch? You still responding to email between golf
swings? Do you remember?


>
> > If you say it works with the current sd- and that the ACB4000 at the
> > other end should work, that's good.
>
> Yes, the sc does work with the current sd and modern drives.  I'll use
> mhitch's patch to check for sure this weekend if the sc+ACB4000
> combination gets a usable drive (beyond not doing INQUIRY).
>
> > There are things beginning to creep in (like Synchronize Cache) that
> > might send such a board into the weeds- you have to see what they
> > do.
>
> Well if we can confidently determine somehow at INQUIRY time that
> we've got an old translator board (and which one!) and conjure up
> a fake INQUIRY response, we should be able to add quirk entries?
>
> > I don't think reading a sun disk label is right (for bootstrap reasons).
>
> Ya, this was just a bad idea.
>
> > But it sounds like this hack will work for the ACB4000. The MT-02 might be
> > another issue (and, no, I no longer have any :-()...
>
> My sun2 has a QIC-02 tape behind another kind of translator board. I'm
> 90% sure it's an MT-02, will check this weekend.

It might be a SYSGEN controller. Just. Say. No.


> My old SunOS 3 installation has a usr/src/sys/sundev/scsi.h that hints
> that the different translator boards return different numbers of sense
> bytes - maybe we can use this to differentiate them?

Oh, gross- yeah, that was the old SunOS hack. No. No. No. It really is a
'per-CPUtype' sort of thing- see below.

-matt

from my version of ncr.c- modifed last in 1994:

static int
ncr_probe(reg, ctlr)
u_short *reg;
int ctlr;
{
	register struct ncrsbc *ncrp = (struct ncrsbc *) reg;
	register struct ncr *ncr;
	long val;
	u_long dma_base, sbcaddr, ctladdr, dmaaddr;
#ifdef	sun3
	u_long udcp;
#endif
	caddr_t dmabuf;
	int host_type = -1;
	u_short *shortp;


	/*
	 * Check for ncr 5380 Scsi Bus Ctlr chip with "peekc()"; struct
	 * ncr-5380 is common to all onboard scsi and vme scsi board. if not
	 * exist, return 0.
	 */

	PRINTF3("ncr_probe: reg= %x virt, %x phys\n", reg,
		getdevaddr((caddr_t) reg));

	/*
	 * We can use the first byte address of reg, 'coz we'll guarantee
	 * (by the time we are through) that that will always be the first
	 * byte of the NCR 5380 SBC (which should be the cbsr register).
	 */

	if (peekc((caddr_t)reg) == -1) {
		return (0);
	}
	sbcaddr = (u_long) reg;
	dmaaddr = ((u_long) reg) + sizeof (struct ncrsbc);

	/*
	 * probe for different host adaptor interfaces
	 */

	switch (cpu) {
#ifdef sun4
	case CPU_SUN4_110:
		/*
		 * probe for 4/110 dma interface
		 */

		ctladdr = ((u_long) reg) + COBRA_CSR_OFF;
		if (peekl((long *) (dmaaddr), (long *) &val) == -1) {
			return (0);
		}
		host_type = IS_COBRA;
		dma_base = DMA_BASE_110;
		break;
#endif	sun4
#ifdef	sun3
	case CPU_SUN3_50:
	case CPU_SUN3_60:
		ctladdr = ((u_long) reg) + CSR_OFF;
		if (peek((short *)&
		    ((struct ncrdma *)dmaaddr)->udc_rdata) == -1)
			return (0);
		udcp = (u_long) IOPBALLOC(sizeof (struct udc_table));

		if (udcp == 0 || udcp & 0x3) {
			printf("%s%d: no udc table\n", CNAME, ctlr);
			if (udcp)
				IOPBFREE(udcp, sizeof (struct udc_table));
			return (0);
		}
		host_type = IS_3_50;
		dma_base = DMA_BASE_3_50;
		break;
#endif	sun3
	default:

		/*
		 * This is either a SCSI-3 or a 3/E VME board
		 *
		 * First see whether the dma address register is there
		 * The low 16 bits is common across all platforms.
		 *
		 */

		if (peek((short *) (dmaaddr + 2)) == -1) {
			return (0);
		}

		/*
		 * Okay, now whether it is a 3/E board
		 */

		ctladdr = ((u_long) reg) + SUN3E_CSR_OFF;
		if (peek((short *) (ctladdr + 2)) != -1) {
			if (poke ((short *) (ctladdr + 2), 0) == 0) {
				if (peek((short *) (ctladdr + 2)) == 0x402) {
					dmabuf = ncr_mapdmabuf(reg);
					if (dmabuf == (caddr_t) 0)
						return (0);
					host_type = IS_3E;
					dma_base = 0;
					break;
				}
			}
		}

		/*
		 * Okay- it wasn't a 3/E. Now see whether it's a scsi-3 board.
		 *
		 * Make sure that it isn't a SCSI-2 board (which occupies 4k
		 * of VME space instead of the 2k that the SCSI-3 occupies).
		 * (the above is a quote from si.c. The code below doesn't
		 *  seem to bear this out exactly).
		 *
		 */


		if (peek((short *) (((u_long) reg) + 0x800)) != -1) {
			return (0);
		}

		/*
		 * Make sure that we're cool (really a scsi-3 board).
		 */

		ctladdr = ((u_long) reg) + CSR_OFF;

		if (peek((short *) (ctladdr + 2)) == -1)
			return (0);

		if ((((struct ncrctl *) ctladdr)->csr.lsw & NCR_CSR_ID) == 0) {
			printf("%s%d: unmodified scsi-3 board- you lose..\n",
				CNAME, ctlr);
			return (0);
		}

		host_type = IS_SCSI3;
		dma_base = 0;
		break;
	}

	/*
	 * Establish initial softc values
	 */

	if (ncr_softc == 0) {
		ncr_softc = (struct ncr *)
			kmem_zalloc((unsigned) (NNCR * sizeof (struct ncr)));
		if (ncr_softc == 0)
			return (0);
		Dmabase = dma_base;
		timeout(ncr_watch, (caddr_t) 0, hz);
	}

	/*
	 * initialize software structure
	 */

	ncr = &ncr_softc[ctlr];
	/*
	 * Allocate a page for being able to
	 * flush the last bit of a data transfer.
	 */
	ncr->n_kment = rmalloc(kernelmap, mmu_btopr(MMU_PAGESIZE));
	if (ncr->n_kment == 0) {
		return (0);
	}
	ncr->n_dev = &ncrdriver;
	ncr->n_id = ncr_host_id;
	ncr->n_sbc = (struct ncrsbc *) (sbcaddr);
	ncr->n_dma = (struct ncrdma *) (dmaaddr);
	ncr->n_ctl = (struct ncrctl *) (ctladdr);
	ncr->n_type = host_type;

	ncr->n_tran.tran_start = ncr_start;
	ncr->n_tran.tran_abort = ncr_abort;
	ncr->n_tran.tran_reset = ncr_reset;
	ncr->n_tran.tran_getcap = ncr_getcap;
	ncr->n_tran.tran_setcap = ncr_setcap;
	ncr->n_tran.tran_pktalloc = scsi_std_pktalloc;
	ncr->n_tran.tran_dmaget = scsi_std_dmaget;
	ncr->n_tran.tran_pktfree = scsi_std_pktfree;
	ncr->n_tran.tran_dmafree = scsi_std_dmafree;

	ncr->n_last_slot = ncr->n_cur_slot = UNDEFINED;
	switch (host_type) {
#ifdef	sun4
	case IS_COBRA:
		ncr->n_dma_setup = ncr_dma_setup;
		ncr->n_dma_cleanup = ncr_cobra_dma_cleanup;
		break;
#endif	sun4
#ifdef	sun3
	case IS_3_50:
		ncr->n_dma_setup = ncr_ob_dma_setup;
		ncr->n_dma_cleanup = ncr_ob_dma_cleanup;
		ncr->n_udc = (struct udc_table *) udcp;
		break;
#endif	sun3
	case IS_SCSI3:
		ncr->n_dma_setup = ncr_dma_setup;
		ncr->n_dma_cleanup = ncr_vme_dma_cleanup;
		break;
	case IS_3E:
		ncr->n_dmabuf = dmabuf;
		ncr->n_dma_setup = ncr_dma_setup;
		ncr->n_dma_cleanup = ncr_3e_dma_cleanup;
		break;
	}

	ncr_internal_reset(ncr, NCR_RESET_ALL, RESET_NOMSG);
	return (NCR_HWSIZE);
}