Home | History | Annotate | Line # | Download | only in dev
sc_wrap.c revision 1.24
      1 /*	$NetBSD: sc_wrap.c,v 1.24 2003/05/10 09:46:25 tsutsui 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 <uvm/uvm_extern.h>
     17 
     18 #include <dev/scsipi/scsi_all.h>
     19 #include <dev/scsipi/scsipi_all.h>
     20 #include <dev/scsipi/scsiconf.h>
     21 #include <dev/scsipi/scsi_message.h>
     22 
     23 #include <newsmips/dev/hbvar.h>
     24 #include <newsmips/dev/scsireg.h>
     25 #include <newsmips/dev/dmac_0448.h>
     26 #include <newsmips/dev/screg_1185.h>
     27 
     28 #include <machine/adrsmap.h>
     29 #include <machine/autoconf.h>
     30 #include <machine/machConst.h>
     31 
     32 #include <mips/cache.h>
     33 
     34 static int cxd1185_match __P((struct device *, struct cfdata *, void *));
     35 static void cxd1185_attach __P((struct device *, struct device *, void *));
     36 
     37 CFATTACH_DECL(sc, sizeof(struct sc_softc),
     38     cxd1185_match, cxd1185_attach, NULL, NULL);
     39 
     40 void cxd1185_init __P((struct sc_softc *));
     41 static void free_scb __P((struct sc_softc *, struct sc_scb *));
     42 static struct sc_scb *get_scb __P((struct sc_softc *, int));
     43 static void sc_scsipi_request __P((struct scsipi_channel *,
     44 					scsipi_adapter_req_t, void *));
     45 static int sc_poll __P((struct sc_softc *, int, int));
     46 static void sc_sched __P((struct sc_softc *));
     47 void sc_done __P((struct sc_scb *));
     48 int sc_intr __P((void *));
     49 static void cxd1185_timeout __P((void *));
     50 
     51 extern void sc_send __P((struct sc_scb *, int, int));
     52 extern int scintr __P((void));
     53 extern void scsi_hardreset __P((void));
     54 extern int sc_busy __P((struct sc_softc *, int));
     55 extern paddr_t kvtophys __P((vaddr_t));
     56 
     57 static int sc_disconnect = IDT_DISCON;
     58 
     59 int
     60 cxd1185_match(parent, cf, aux)
     61 	struct device *parent;
     62 	struct cfdata *cf;
     63 	void *aux;
     64 {
     65 	struct hb_attach_args *ha = aux;
     66 
     67 	if (strcmp(ha->ha_name, "sc"))
     68 		return 0;
     69 
     70 	return 1;
     71 }
     72 
     73 void
     74 cxd1185_attach(parent, self, aux)
     75 	struct device *parent, *self;
     76 	void *aux;
     77 {
     78 	struct sc_softc *sc = (void *)self;
     79 	struct hb_attach_args *ha = aux;
     80 	struct sc_scb *scb;
     81 	int i, intlevel;
     82 
     83 	intlevel = ha->ha_level;
     84 	if (intlevel == -1) {
     85 #if 0
     86 		printf(": interrupt level not configured\n");
     87 		return;
     88 #else
     89 		printf(": interrupt level not configured; using");
     90 		intlevel = 0;
     91 #endif
     92 	}
     93 	printf(" level %d\n", intlevel);
     94 
     95 	if (sc_idenr & 0x08)
     96 		sc->scsi_1185AQ = 1;
     97 	else
     98 		sc->scsi_1185AQ = 0;
     99 
    100 	sc->sc_adapter.adapt_dev = &sc->sc_dev;
    101 	sc->sc_adapter.adapt_nchannels = 1;
    102 	sc->sc_adapter.adapt_openings = 7;
    103 	sc->sc_adapter.adapt_max_periph = 1;
    104 	sc->sc_adapter.adapt_ioctl = NULL;
    105 	sc->sc_adapter.adapt_minphys = minphys;
    106 	sc->sc_adapter.adapt_request = sc_scsipi_request;
    107 
    108 	memset(&sc->sc_channel, 0, sizeof(sc->sc_channel));
    109 	sc->sc_channel.chan_adapter = &sc->sc_adapter;
    110 	sc->sc_channel.chan_bustype = &scsi_bustype;
    111 	sc->sc_channel.chan_channel = 0;
    112 	sc->sc_channel.chan_ntargets = 8;
    113 	sc->sc_channel.chan_nluns = 8;
    114 	sc->sc_channel.chan_id = 7;
    115 
    116 	TAILQ_INIT(&sc->ready_list);
    117 	TAILQ_INIT(&sc->free_list);
    118 
    119 	scb = sc->sc_scb;
    120 	for (i = 0; i < 24; i++) {	/* XXX 24 */
    121 		TAILQ_INSERT_TAIL(&sc->free_list, scb, chain);
    122 		scb++;
    123 	}
    124 
    125 	cxd1185_init(sc);
    126 	DELAY(100000);
    127 
    128 	hb_intr_establish(intlevel, INTEN1_DMA, IPL_BIO, sc_intr, sc);
    129 
    130 	config_found(&sc->sc_dev, &sc->sc_channel, scsiprint);
    131 }
    132 
    133 void
    134 cxd1185_init(sc)
    135 	struct sc_softc *sc;
    136 {
    137 	int i;
    138 
    139 	for (i = 0; i < 8; i++)
    140 		sc->inuse[i] = 0;
    141 
    142 	scsi_hardreset();
    143 }
    144 
    145 void
    146 free_scb(sc, scb)
    147 	struct sc_softc *sc;
    148 	struct sc_scb *scb;
    149 {
    150 	int s;
    151 
    152 	s = splbio();
    153 
    154 	TAILQ_INSERT_HEAD(&sc->free_list, scb, chain);
    155 
    156 	/*
    157 	 * If there were none, wake anybody waiting for one to come free,
    158 	 * starting with queued entries.
    159 	 */
    160 	if (scb->chain.tqe_next == 0)
    161 		wakeup(&sc->free_list);
    162 
    163 	splx(s);
    164 }
    165 
    166 struct sc_scb *
    167 get_scb(sc, flags)
    168 	struct sc_softc *sc;
    169 	int flags;
    170 {
    171 	int s;
    172 	struct sc_scb *scb;
    173 
    174 	s = splbio();
    175 
    176 	while ((scb = sc->free_list.tqh_first) == NULL &&
    177 		(flags & XS_CTL_NOSLEEP) == 0)
    178 		tsleep(&sc->free_list, PRIBIO, "sc_scb", 0);
    179 	if (scb) {
    180 		TAILQ_REMOVE(&sc->free_list, scb, chain);
    181 	}
    182 
    183 	splx(s);
    184 	return scb;
    185 }
    186 
    187 void
    188 sc_scsipi_request(chan, req, arg)
    189 	struct scsipi_channel *chan;
    190 	scsipi_adapter_req_t req;
    191 	void *arg;
    192 {
    193 	struct scsipi_xfer *xs;
    194 	struct scsipi_periph *periph;
    195 	struct sc_softc *sc = (void *)chan->chan_adapter->adapt_dev;
    196 	struct sc_scb *scb;
    197 	int flags, s;
    198 	int target;
    199 
    200 	switch (req) {
    201 	case ADAPTER_REQ_RUN_XFER:
    202 		xs = arg;
    203 		periph = xs->xs_periph;
    204 
    205 		flags = xs->xs_control;
    206 		if ((scb = get_scb(sc, flags)) == NULL)
    207 			panic("sc_scsipi_request: no scb");
    208 
    209 		scb->xs = xs;
    210 		scb->flags = 0;
    211 		scb->sc_ctag = 0;
    212 		scb->sc_coffset = 0;
    213 		scb->istatus = 0;
    214 		scb->tstatus = 0;
    215 		scb->message = 0;
    216 		bzero(scb->msgbuf, sizeof(scb->msgbuf));
    217 
    218 		s = splbio();
    219 
    220 		TAILQ_INSERT_TAIL(&sc->ready_list, scb, chain);
    221 		sc_sched(sc);
    222 		splx(s);
    223 
    224 		if (flags & XS_CTL_POLL) {
    225 			target = periph->periph_target;
    226 			if (sc_poll(sc, target, xs->timeout)) {
    227 				printf("sc: timeout (retry)\n");
    228 				if (sc_poll(sc, target, xs->timeout)) {
    229 					printf("sc: timeout\n");
    230 				}
    231 			}
    232 			/* called during autoconfig only... */
    233 			mips_dcache_wbinv_all();	/* Flush DCache */
    234 		}
    235 		return;
    236 	case ADAPTER_REQ_GROW_RESOURCES:
    237 		/* XXX Not supported. */
    238 		return;
    239 	case ADAPTER_REQ_SET_XFER_MODE:
    240 		/* XXX Not supported. */
    241 		return;
    242 	}
    243 }
    244 
    245 /*
    246  * Used when interrupt driven I/O isn't allowed, e.g. during boot.
    247  */
    248 int
    249 sc_poll(sc, chan, count)
    250 	struct sc_softc *sc;
    251 	int chan, count;
    252 {
    253 	volatile u_char *int_stat = (void *)INTST1;
    254 	volatile u_char *int_clear = (void *)INTCLR1;
    255 
    256 	while (sc_busy(sc, chan)) {
    257 		if (*int_stat & INTST1_DMA) {
    258 		    *int_clear = INTST1_DMA;
    259 		    if (dmac_gstat & CH_INT(CH_SCSI)) {
    260 			if (dmac_gstat & CH_MRQ(CH_SCSI)) {
    261 			    DELAY(50);
    262 			    if (dmac_gstat & CH_MRQ(CH_SCSI))
    263 				printf("dma_poll\n");
    264 			}
    265 			DELAY(10);
    266 			scintr();
    267 		    }
    268 		}
    269 		DELAY(1000);
    270 		count--;
    271 		if (count <= 0)
    272 			return 1;
    273 	}
    274 	return 0;
    275 }
    276 
    277 void
    278 sc_sched(sc)
    279 	struct sc_softc *sc;
    280 {
    281 	struct scsipi_xfer *xs;
    282 	struct scsipi_periph *periph;
    283 	int ie = 0;
    284 	int flags;
    285 	int chan, lun;
    286 	struct sc_scb *scb, *nextscb;
    287 
    288 	scb = sc->ready_list.tqh_first;
    289 start:
    290 	if (scb == NULL)
    291 		return;
    292 
    293 	xs = scb->xs;
    294 	periph = xs->xs_periph;
    295 	chan = periph->periph_target;
    296 	flags = xs->xs_control;
    297 
    298 	if (cold)
    299 		flags |= XS_CTL_POLL;
    300 
    301 	if (sc->inuse[chan]) {
    302 		scb = scb->chain.tqe_next;
    303 		goto start;
    304 	}
    305 	sc->inuse[chan] = 1;
    306 
    307 	if (flags & XS_CTL_RESET)
    308 		printf("SCSI RESET\n");
    309 
    310 	lun = periph->periph_lun;
    311 
    312 	scb->identify = MSG_IDENT | sc_disconnect | (lun & IDT_DRMASK);
    313 	scb->sc_ctrnscnt = xs->datalen;
    314 
    315 	/* make va->pa mapping table for DMA */
    316 	if (xs->datalen > 0) {
    317 		int pages, offset;
    318 		int i, pn;
    319 		vaddr_t va;
    320 
    321 		/* bzero(&sc->sc_map[chan], sizeof(struct sc_map)); */
    322 
    323 		va = (vaddr_t)xs->data;
    324 
    325 		offset = va & PGOFSET;
    326 		pages = (offset + xs->datalen + PAGE_SIZE -1 ) >> PGSHIFT;
    327 		if (pages >= NSCMAP)
    328 			panic("sc_map: Too many pages");
    329 
    330 		for (i = 0; i < pages; i++) {
    331 			pn = kvtophys(va) >> PGSHIFT;
    332 			sc->sc_map[chan].mp_addr[i] = pn;
    333 			va += PAGE_SIZE;
    334 		}
    335 
    336 		sc->sc_map[chan].mp_offset = offset;
    337 		sc->sc_map[chan].mp_pages = pages;
    338 		scb->sc_map = &sc->sc_map[chan];
    339 	}
    340 
    341 	if ((flags & XS_CTL_POLL) == 0)
    342 		ie = SCSI_INTEN;
    343 
    344 	if (xs->data)
    345 		scb->sc_cpoint = (void *)xs->data;
    346 	else
    347 		scb->sc_cpoint = scb->msgbuf;
    348 	scb->scb_softc = sc;
    349 
    350 	callout_reset(&scb->xs->xs_callout, hz * 10, cxd1185_timeout, scb);
    351 	sc_send(scb, chan, ie);
    352 	callout_stop(&scb->xs->xs_callout);
    353 
    354 	nextscb = scb->chain.tqe_next;
    355 
    356 	TAILQ_REMOVE(&sc->ready_list, scb, chain);
    357 
    358 	scb = nextscb;
    359 
    360 	goto start;
    361 }
    362 
    363 void
    364 sc_done(scb)
    365 	struct sc_scb *scb;
    366 {
    367 	struct scsipi_xfer *xs = scb->xs;
    368 	struct scsipi_periph *periph = xs->xs_periph;
    369 	struct sc_softc *sc = (void *)periph->periph_channel->chan_adapter->adapt_dev;
    370 
    371 	xs->resid = 0;
    372 	xs->status = 0;
    373 
    374 	if (scb->istatus != INST_EP) {
    375 		if (scb->istatus == (INST_EP|INST_TO))
    376 			xs->error = XS_SELTIMEOUT;
    377 		else {
    378 			printf("SC(i): [istatus=0x%x, tstatus=0x%x]\n",
    379 				scb->istatus, scb->tstatus);
    380 			xs->error = XS_DRIVER_STUFFUP;
    381 		}
    382 	}
    383 
    384 	switch (scb->tstatus) {
    385 
    386 	case TGST_GOOD:
    387 		break;
    388 
    389 	case TGST_CC:
    390 		xs->status = SCSI_CHECK;
    391 		if (xs->error == 0)
    392 			xs->error = XS_BUSY;
    393 
    394 	default:
    395 		printf("SC(t): [istatus=0x%x, tstatus=0x%x]\n",
    396 			scb->istatus, scb->tstatus);
    397 		break;
    398 	}
    399 
    400 	scsipi_done(xs);
    401 	free_scb(sc, scb);
    402 	sc->inuse[periph->periph_target] = 0;
    403 	sc_sched(sc);
    404 }
    405 
    406 int
    407 sc_intr(v)
    408 	void *v;
    409 {
    410 	/* struct sc_softc *sc = v; */
    411 	volatile u_char *gsp = (u_char *)DMAC_GSTAT;
    412 	u_int gstat = *gsp;
    413 	int mrqb, i;
    414 
    415 	if ((gstat & CH_INT(CH_SCSI)) == 0)
    416 		return 0;
    417 
    418 	/*
    419 	 * when DMA interrupt occurs there remain some untransferred data.
    420 	 * wait data transfer completion.
    421 	 */
    422 	mrqb = (gstat & CH_INT(CH_SCSI)) << 1;
    423 	if (gstat & mrqb) {
    424 		/*
    425 		 * XXX SHOULD USE DELAY()
    426 		 */
    427 		for (i = 0; i < 50; i++)
    428 			;
    429 		if (*gsp & mrqb)
    430 			printf("sc_intr: MRQ\n");
    431 	}
    432 	scintr();
    433 
    434 	return 1;
    435 }
    436 
    437 
    438 #if 0
    439 /*
    440  * SCOP_RSENSE request
    441  */
    442 void
    443 scop_rsense(intr, sc_param, lun, ie, count, param)
    444 	register int intr;
    445 	register struct scsi *sc_param;
    446 	register int lun;
    447 	register int ie;
    448 	register int count;
    449 	register caddr_t param;
    450 {
    451 	bzero(sc_param, sizeof(struct scsi));
    452 	sc_param->identify = MSG_IDENT | sc_disconnect | (lun & IDT_DRMASK);
    453 	sc_param->sc_lun = lun;
    454 
    455 	sc_param->sc_cpoint = (u_char *)param;
    456 	sc_param->sc_ctrnscnt = count;
    457 
    458 	/* sc_cdb */
    459 	sc_param->sc_opcode = SCOP_RSENSE;
    460 	sc_param->sc_count = count;
    461 
    462 	sc_go(intr, sc_param, ie, sc_param);
    463 }
    464 #endif
    465 
    466 void
    467 cxd1185_timeout(arg)
    468 	void *arg;
    469 {
    470 	struct sc_scb *scb = arg;
    471 	struct scsipi_xfer *xs = scb->xs;
    472 	struct scsipi_periph *periph = xs->xs_periph;
    473 	int chan;
    474 
    475 	chan = periph->periph_target;
    476 
    477 	printf("sc: timeout ch=%d\n", chan);
    478 
    479 	/* XXX abort transfer and ... */
    480 }
    481