Home | History | Annotate | Line # | Download | only in dev
sc_wrap.c revision 1.7
      1 /*	$NetBSD: sc_wrap.c,v 1.7 1998/10/10 00:28:31 thorpej Exp $	*/
      2 
      3 /*
      4  * This driver is slow!  Need to rewrite.
      5  */
      6 
      7 #include <sys/types.h>
      8 #include <sys/param.h>
      9 #include <sys/systm.h>
     10 #include <sys/kernel.h>
     11 #include <sys/device.h>
     12 #include <sys/proc.h>
     13 #include <sys/buf.h>
     14 #include <sys/malloc.h>
     15 
     16 #include <dev/scsipi/scsi_all.h>
     17 #include <dev/scsipi/scsipi_all.h>
     18 #include <dev/scsipi/scsiconf.h>
     19 #include <dev/scsipi/scsi_message.h>
     20 
     21 #include <newsmips/dev/scsireg.h>
     22 #include <newsmips/dev/dmac_0448.h>
     23 #include <newsmips/dev/screg_1185.h>
     24 
     25 #include <machine/locore.h>
     26 #include <machine/adrsmap.h>
     27 #include <machine/autoconf.h>
     28 #include <machine/machConst.h>
     29 
     30 extern int cold;
     31 
     32 static int cxd1185_match __P((struct device *, struct cfdata *, void *));
     33 static void cxd1185_attach __P((struct device *, struct device *, void *));
     34 
     35 struct cfattach sc_ca = {
     36 	sizeof(struct sc_softc), cxd1185_match, cxd1185_attach
     37 };
     38 
     39 void cxd1185_init __P((struct sc_softc *));
     40 static void free_scb __P((struct sc_softc *, struct sc_scb *));
     41 static struct sc_scb *get_scb __P((struct sc_softc *, int));
     42 static int sc_scsi_cmd __P((struct scsipi_xfer *));
     43 static int sc_poll __P((struct sc_softc *, int, int));
     44 static void sc_sched __P((struct sc_softc *));
     45 void sc_done __P((struct sc_scb *));
     46 int sc_intr __P((struct sc_softc *));
     47 static void cxd1185_timeout __P((void *));
     48 
     49 extern void sc_send __P((struct sc_scb *, int, int));
     50 extern int scintr __P((void));
     51 extern void scsi_hardreset __P((void));
     52 extern int sc_busy __P((struct sc_softc *, int));
     53 extern paddr_t kvtophys __P((vaddr_t));
     54 
     55 static int sc_disconnect = IDT_DISCON;
     56 
     57 struct scsipi_adapter cxd1185_switch = {
     58 	sc_scsi_cmd,
     59 	minphys,
     60 	NULL,		/* scsipi_ioctl */
     61 };
     62 
     63 struct scsipi_device cxd1185_dev = {
     64 	NULL,
     65 	NULL,
     66 	NULL,
     67 	NULL
     68 };
     69 
     70 int
     71 cxd1185_match(parent, cf, aux)
     72 	struct device *parent;
     73 	struct cfdata *cf;
     74 	void *aux;
     75 {
     76 	struct confargs *ca = aux;
     77 
     78 	if (strcmp(ca->ca_name, "sc"))
     79 		return 0;
     80 
     81 	return 1;
     82 }
     83 
     84 void
     85 cxd1185_attach(parent, self, aux)
     86 	struct device *parent, *self;
     87 	void *aux;
     88 {
     89 	struct sc_softc *sc = (void *)self;
     90 	struct sc_scb *scb;
     91 	int i;
     92 
     93 	if (sc_idenr & 0x08)
     94 		sc->scsi_1185AQ = 1;
     95 	else
     96 		sc->scsi_1185AQ = 0;
     97 
     98 	sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
     99 	sc->sc_link.adapter_softc = sc;
    100 	sc->sc_link.scsipi_scsi.adapter_target = 7;
    101 	sc->sc_link.adapter = &cxd1185_switch;
    102 	sc->sc_link.device = &cxd1185_dev;
    103 	sc->sc_link.openings = 2;
    104 	sc->sc_link.scsipi_scsi.max_target = 7;
    105 	sc->sc_link.type = BUS_SCSI;
    106 
    107 	TAILQ_INIT(&sc->ready_list);
    108 	TAILQ_INIT(&sc->free_list);
    109 
    110 	scb = sc->sc_scb;
    111 	for (i = 0; i < 24; i++) {	/* XXX 24 */
    112 		TAILQ_INSERT_TAIL(&sc->free_list, scb, chain);
    113 		scb++;
    114 	}
    115 
    116 	cxd1185_init(sc);
    117 	DELAY(100000);
    118 
    119 	printf("\n");
    120 	config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
    121 }
    122 
    123 void
    124 cxd1185_init(sc)
    125 	struct sc_softc *sc;
    126 {
    127 	int i;
    128 
    129 	for (i = 0; i < 8; i++)
    130 		sc->inuse[i] = 0;
    131 
    132 	scsi_hardreset();
    133 }
    134 
    135 void
    136 free_scb(sc, scb)
    137 	struct sc_softc *sc;
    138 	struct sc_scb *scb;
    139 {
    140 	int s;
    141 
    142 	s = splbio();
    143 
    144 	TAILQ_INSERT_HEAD(&sc->free_list, scb, chain);
    145 
    146 	/*
    147 	 * If there were none, wake anybody waiting for one to come free,
    148 	 * starting with queued entries.
    149 	 */
    150 	if (scb->chain.tqe_next == 0)
    151 		wakeup(&sc->free_list);
    152 
    153 	splx(s);
    154 }
    155 
    156 struct sc_scb *
    157 get_scb(sc, flags)
    158 	struct sc_softc *sc;
    159 	int flags;
    160 {
    161 	int s;
    162 	struct sc_scb *scb;
    163 
    164 	s = splbio();
    165 
    166 	while ((scb = sc->free_list.tqh_first) == NULL &&
    167 		(flags & SCSI_NOSLEEP) == 0)
    168 		tsleep(&sc->free_list, PRIBIO, "sc_scb", 0);
    169 	if (scb) {
    170 		TAILQ_REMOVE(&sc->free_list, scb, chain);
    171 	}
    172 
    173 	splx(s);
    174 	return scb;
    175 }
    176 
    177 int
    178 sc_scsi_cmd(xs)
    179 	struct scsipi_xfer *xs;
    180 {
    181 	struct scsipi_link *sc_link = xs->sc_link;
    182 	struct sc_softc *sc = sc_link->adapter_softc;
    183 	struct sc_scb *scb;
    184 	int flags, s;
    185 	int chan;
    186 
    187 	flags = xs->flags;
    188 	if ((scb = get_scb(sc, flags)) == NULL)
    189 		return TRY_AGAIN_LATER;
    190 
    191 	scb->xs = xs;
    192 	scb->flags = 0;
    193 	scb->sc_ctag = 0;
    194 	scb->sc_coffset = 0;
    195 	scb->istatus = 0;
    196 	scb->tstatus = 0;
    197 	scb->message = 0;
    198 	bzero(scb->msgbuf, sizeof(scb->msgbuf));
    199 
    200 	s = splbio();
    201 
    202 	TAILQ_INSERT_TAIL(&sc->ready_list, scb, chain);
    203 	sc_sched(sc);
    204 	splx(s);
    205 
    206 	if ((flags & SCSI_POLL) == 0)
    207 		return SUCCESSFULLY_QUEUED;
    208 
    209 	chan = sc_link->scsipi_scsi.target;
    210 
    211 	if (sc_poll(sc, chan, xs->timeout)) {
    212 		printf("sc: timeout (retry)\n");
    213 		if (sc_poll(sc, chan, xs->timeout)) {
    214 			printf("sc: timeout\n");
    215 			return COMPLETE;
    216 		}
    217 	}
    218 
    219 	/* called during autoconfig only... */
    220 
    221 	MachFlushCache(); /* Flush all caches */
    222 	return COMPLETE;
    223 }
    224 
    225 /*
    226  * Used when interrupt driven I/O isn't allowed, e.g. during boot.
    227  */
    228 int
    229 sc_poll(sc, chan, count)
    230 	struct sc_softc *sc;
    231 	int chan, count;
    232 {
    233 	volatile u_char *int_stat = (void *)INTST1;
    234 	volatile u_char *int_clear = (void *)INTCLR1;
    235 
    236 	while (sc_busy(sc, chan)) {
    237 		if (*int_stat & INTST1_DMA) {
    238 		    *int_clear = INTST1_DMA;
    239 		    if (dmac_gstat & CH_INT(CH_SCSI)) {
    240 			if (dmac_gstat & CH_MRQ(CH_SCSI)) {
    241 			    DELAY(50);
    242 			    if (dmac_gstat & CH_MRQ(CH_SCSI))
    243 				printf("dma_poll\n");
    244 			}
    245 			DELAY(10);
    246 			scintr();
    247 		    }
    248 		}
    249 		DELAY(1000);
    250 		count--;
    251 		if (count <= 0)
    252 			return 1;
    253 	}
    254 	return 0;
    255 }
    256 
    257 void
    258 sc_sched(sc)
    259 	struct sc_softc *sc;
    260 {
    261 	struct scsipi_xfer *xs;
    262 	struct scsipi_link *sc_link;
    263 	int ie = 0;
    264 	int flags;
    265 	int chan, lun;
    266 	struct sc_scb *scb, *nextscb;
    267 
    268 	scb = sc->ready_list.tqh_first;
    269 start:
    270 	if (scb == NULL)
    271 		return;
    272 
    273 	xs = scb->xs;
    274 	sc_link = xs->sc_link;
    275 	chan = sc_link->scsipi_scsi.target;
    276 	flags = xs->flags;
    277 
    278 	if (cold)
    279 		flags |= SCSI_POLL;
    280 
    281 	if (sc->inuse[chan]) {
    282 		scb = scb->chain.tqe_next;
    283 		goto start;
    284 	}
    285 	sc->inuse[chan] = 1;
    286 
    287 	if (flags & SCSI_RESET)
    288 		printf("SCSI RESET\n");
    289 
    290 	lun = sc_link->scsipi_scsi.lun;
    291 
    292 	scb->identify = MSG_IDENT | sc_disconnect | (lun & IDT_DRMASK);
    293 	scb->sc_ctrnscnt = xs->datalen;
    294 
    295 	/* make va->pa mapping table for dma */
    296 	if (xs->datalen > 0) {
    297 		int pages, offset;
    298 		int i, pn;
    299 		vaddr_t va;
    300 
    301 		/* bzero(&sc->sc_map[chan], sizeof(struct sc_map)); */
    302 
    303 		va = (vaddr_t)xs->data;
    304 
    305 		offset = va & PGOFSET;
    306 		pages = (offset + xs->datalen + NBPG -1 ) >> PGSHIFT;
    307 		if (pages >= NSCMAP)
    308 			panic("sc_map: Too many pages");
    309 
    310 		for (i = 0; i < pages; i++) {
    311 			pn = kvtophys(va) >> PGSHIFT;
    312 			sc->sc_map[chan].mp_addr[i] = pn;
    313 			va += NBPG;
    314 		}
    315 
    316 		sc->sc_map[chan].mp_offset = offset;
    317 		sc->sc_map[chan].mp_pages = pages;
    318 		scb->sc_map = &sc->sc_map[chan];
    319 	}
    320 
    321 	if ((flags & SCSI_POLL) == 0)
    322 		ie = SCSI_INTEN;
    323 
    324 	if (xs->data)
    325 		scb->sc_cpoint = (void *)xs->data;
    326 	else
    327 		scb->sc_cpoint = scb->msgbuf;
    328 	scb->scb_softc = sc;
    329 
    330 	timeout(cxd1185_timeout, scb, hz * 10);
    331 	sc_send(scb, chan, ie);
    332 	untimeout(cxd1185_timeout, scb);
    333 
    334 	nextscb = scb->chain.tqe_next;
    335 
    336 	TAILQ_REMOVE(&sc->ready_list, scb, chain);
    337 
    338 	scb = nextscb;
    339 
    340 	goto start;
    341 }
    342 
    343 void
    344 sc_done(scb)
    345 	struct sc_scb *scb;
    346 {
    347 	struct scsipi_xfer *xs = scb->xs;
    348 	struct scsipi_link *sc_link = xs->sc_link;
    349 	struct sc_softc *sc = sc_link->adapter_softc;
    350 
    351 	xs->flags |= ITSDONE;
    352 	xs->resid = 0;
    353 	xs->status = 0;
    354 
    355 	if (scb->istatus != INST_EP) {
    356 		if (! cold)
    357 			printf("SC(i): [istatus=0x%x, tstatus=0x%x]\n",
    358 				scb->istatus, scb->tstatus);
    359 		xs->error = XS_DRIVER_STUFFUP;
    360 	}
    361 
    362 	switch (scb->tstatus) {
    363 
    364 	case TGST_GOOD:
    365 		break;
    366 
    367 	case TGST_CC:
    368 		break;		/* XXX */
    369 #if 0
    370 		chan = sc_link->scsipi_scsi.target;
    371 		lun = sc_link->scsipi_scsi.lun;
    372 		scop_rsense(chan, scb, lun, SCSI_INTDIS, 18, 0);
    373 		if (scb->tstatus != TGST_GOOD) {
    374 			printf("SC(t2): [istatus=0x%x, tstatus=0x%x]\n",
    375 				scb->istatus, scb->tstatus);
    376 		}
    377 #endif
    378 
    379 	default:
    380 		printf("SC(t): [istatus=0x%x, tstatus=0x%x]\n",
    381 			scb->istatus, scb->tstatus);
    382 		break;
    383 	}
    384 
    385 	scsipi_done(xs);
    386 	free_scb(sc, scb);
    387 	sc->inuse[sc_link->scsipi_scsi.target] = 0;
    388 	sc_sched(sc);
    389 }
    390 
    391 int
    392 sc_intr(sc)
    393 	struct sc_softc *sc;
    394 {
    395 	return scintr();
    396 }
    397 
    398 
    399 #if 0
    400 /*
    401  * SCOP_RSENSE request
    402  */
    403 void
    404 scop_rsense(intr, sc_param, lun, ie, count, param)
    405 	register int intr;
    406 	register struct scsi *sc_param;
    407 	register int lun;
    408 	register int ie;
    409 	register int count;
    410 	register caddr_t param;
    411 {
    412 	bzero(sc_param, sizeof(struct scsi));
    413 	sc_param->identify = MSG_IDENT | sc_disconnect | (lun & IDT_DRMASK);
    414 	sc_param->sc_lun = lun;
    415 
    416 	sc_param->sc_cpoint = (u_char *)param;
    417 	sc_param->sc_ctrnscnt = count;
    418 
    419 	/* sc_cdb */
    420 	sc_param->sc_opcode = SCOP_RSENSE;
    421 	sc_param->sc_count = count;
    422 
    423 	sc_go(intr, sc_param, ie, sc_param);
    424 }
    425 #endif
    426 
    427 void
    428 cxd1185_timeout(arg)
    429 	void *arg;
    430 {
    431 	struct sc_scb *scb = arg;
    432 	struct scsipi_xfer *xs = scb->xs;
    433 	struct scsipi_link *sc_link = xs->sc_link;
    434 	int chan;
    435 
    436 	chan = sc_link->scsipi_scsi.target;
    437 
    438 	printf("sc: timeout ch=%d\n", chan);
    439 
    440 	/* XXX abort transfer and ... */
    441 }
    442