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