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