Annotation of sys/arch/mvme68k/dev/vs.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: vs.c,v 1.20 2006/06/02 18:53:56 miod Exp $ */
2:
3: /*
4: * Copyright (c) 1999 Steve Murphree, Jr.
5: * Copyright (c) 1990 The Regents of the University of California.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * Van Jacobson of Lawrence Berkeley Laboratory.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: /*
37: * MVME328 scsi adaptor driver
38: */
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/device.h>
43: #include <sys/disklabel.h>
44: #include <sys/dkstat.h>
45: #include <sys/buf.h>
46: #include <sys/malloc.h>
47:
48: #include <scsi/scsi_all.h>
49: #include <scsi/scsiconf.h>
50:
51: #include <machine/autoconf.h>
52: #include <machine/param.h>
53:
54: #include <uvm/uvm_param.h>
55:
56: #ifdef mvme88k
57: #include <mvme88k/dev/vsreg.h>
58: #include <mvme88k/dev/vsvar.h>
59: #include <machine/mmu.h>
60: #else
61: #include <mvme68k/dev/vsreg.h>
62: #include <mvme68k/dev/vsvar.h>
63: #endif
64:
65: void scopy(void *, void *, u_int);
66: void szero(void *, u_int);
67: int do_vspoll(struct vs_softc *, int, int);
68: void thaw_queue(struct vs_softc *, u_int8_t);
69: int vs_checkintr(struct vs_softc *, struct scsi_xfer *, int *);
70: void vs_chksense(struct scsi_xfer *);
71: void vs_reset(struct vs_softc *);
72: void vs_resync(struct vs_softc *);
73: void vs_initialize(struct vs_softc *);
74: void vs_intr(void *);
75: int vs_poll(struct vs_softc *, struct scsi_xfer *);
76: void vs_scsidone(struct scsi_xfer *, int);
77: M328_CQE *vs_getcqe(struct vs_softc *);
78: M328_IOPB *vs_getiopb(struct vs_softc *);
79: void vs_link_sg_element(sg_list_element_t *, vaddr_t, int);
80: void vs_link_sg_list(sg_list_element_t *, vaddr_t, int);
81:
82: /*
83: * 16 bit 's' memory functions. MVME328 is a D16 board.
84: * We must program with that in mind or else...
85: * bcopy/bzero (the 'b' meaning byte) is implemented in
86: * 32 bit operations for speed, so thay are not really
87: * 'byte' operations at all!! MVME1x7 can be set up to
88: * handle D32 -> D16 read/writes via VMEChip2 Address
89: * modifiers, however MVME188 can not. These next two
90: * functions insure 16 bit copy/zero operations. The
91: * structures are all implemented with 16 bit or less
92: * types. smurph
93: */
94:
95: void
96: scopy(src, dst, cnt)
97: void *src, *dst;
98: u_int cnt;
99: {
100: u_int16_t volatile *x, *y, z;
101:
102: z = cnt >> 1;
103: x = (u_int16_t *) src;
104: y = (u_int16_t *) dst;
105:
106: while (z--) {
107: *y++ = *x++;
108: }
109: }
110:
111: void
112: szero(src, cnt)
113: void *src;
114: u_int cnt;
115: {
116: u_int16_t *source;
117: u_int16_t zero = 0;
118: u_int16_t z;
119:
120: source = (u_int16_t *) src;
121: z = cnt >> 1;
122:
123: while (z--) {
124: *source++ = zero;
125: }
126: }
127:
128: /*
129: * default minphys routine for MVME328 based controllers
130: */
131: void
132: vs_minphys(bp)
133: struct buf *bp;
134: {
135: /*
136: * No max transfer at this level.
137: */
138: minphys(bp);
139: }
140:
141: int
142: do_vspoll(sc, to, canreset)
143: struct vs_softc *sc;
144: int to;
145: int canreset;
146: {
147: int i;
148:
149: if (to <= 0 ) to = 50000;
150: /* use cmd_wait values? */
151: i = 50000;
152: /*spl0();*/
153: while (!(CRSW & (M_CRSW_CRBV | M_CRSW_CC))) {
154: if (--i <= 0) {
155: #ifdef DEBUG
156: printf ("waiting: timeout %d crsw 0x%x\n", to, CRSW);
157: #endif
158: i = 50000;
159: --to;
160: if (to <= 0) {
161: /*splx(s);*/
162: if (canreset) {
163: vs_reset(sc);
164: vs_resync(sc);
165: }
166: printf ("timed out: timeout %d crsw 0x%x\n",
167: to, CRSW);
168: return 1;
169: }
170: }
171: }
172: return 0;
173: }
174:
175: int
176: vs_poll(sc, xs)
177: struct vs_softc *sc;
178: struct scsi_xfer *xs;
179: {
180: int status;
181: int to;
182:
183: /*s = splbio();*/
184: to = xs->timeout / 1000;
185: for (;;) {
186: if (do_vspoll(sc, to, 1)) break;
187: if (vs_checkintr(sc, xs, &status)) {
188: vs_scsidone(xs, status);
189: }
190: if (CRSW & M_CRSW_ER)
191: CRB_CLR_ER(CRSW);
192: CRB_CLR_DONE(CRSW);
193: if (xs->flags & ITSDONE) break;
194: }
195: return (COMPLETE);
196: }
197:
198: void
199: thaw_queue(sc, target)
200: struct vs_softc *sc;
201: u_int8_t target;
202: {
203: u_short t;
204: t = target << 8;
205: t |= 0x0001;
206: THAW_REG = t;
207: /* loop until thawed */
208: while (THAW_REG & 0x01);
209: }
210:
211: void
212: vs_scsidone (xs, stat)
213: struct scsi_xfer *xs;
214: int stat;
215: {
216: struct scsi_link *slp = xs->sc_link;
217: struct vs_softc *sc = slp->adapter_softc;
218: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
219:
220: xs->status = stat;
221: while (xs->status == SCSI_CHECK) {
222: vs_chksense(xs);
223: thaw_queue(sc, slp->target + 1);
224: }
225: xs->flags |= ITSDONE;
226: /*sc->sc_tinfo[slp->target].cmds++;*/
227: if (CRSW & M_CRSW_ER)
228: CRB_CLR_ER(CRSW);
229: CRB_CLR_DONE(CRSW);
230: thaw_queue(sc, slp->target + 1);
231: szero(riopb, sizeof(M328_IOPB));
232: scsi_done(xs);
233: }
234:
235: int
236: vs_scsicmd(xs)
237: struct scsi_xfer *xs;
238: {
239: struct scsi_link *slp = xs->sc_link;
240: struct vs_softc *sc = slp->adapter_softc;
241: int flags;
242: unsigned long buf, len;
243: u_short iopb_len;
244: M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE;
245: M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB;
246: M328_IOPB *miopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB;
247: M328_CQE *cqep;
248: M328_IOPB *iopb;
249: M328_CMD *m328_cmd;
250:
251: /* If the target doesn't exist, abort */
252: if (!sc->sc_tinfo[slp->target].avail) {
253: xs->error = XS_SELTIMEOUT;
254: xs->status = -1;
255: xs->flags |= ITSDONE;
256: scsi_done(xs);
257: }
258:
259: flags = xs->flags;
260: #ifdef SDEBUG
261: printf("scsi_cmd() ");
262: if (xs->cmd->opcode == 0) {
263: printf("TEST_UNIT_READY ");
264: } else if (xs->cmd->opcode == REQUEST_SENSE) {
265: printf("REQUEST_SENSE ");
266: } else if (xs->cmd->opcode == INQUIRY) {
267: printf("INQUIRY ");
268: } else if (xs->cmd->opcode == MODE_SELECT) {
269: printf("MODE_SELECT ");
270: } else if (xs->cmd->opcode == MODE_SENSE) {
271: printf("MODE_SENSE ");
272: } else if (xs->cmd->opcode == START_STOP) {
273: printf("START_STOP ");
274: } else if (xs->cmd->opcode == RESERVE) {
275: printf("RESERVE ");
276: } else if (xs->cmd->opcode == RELEASE) {
277: printf("RELEASE ");
278: } else if (xs->cmd->opcode == PREVENT_ALLOW) {
279: printf("PREVENT_ALLOW ");
280: } else if (xs->cmd->opcode == POSITION_TO_ELEMENT) {
281: printf("POSITION_TO_EL ");
282: } else if (xs->cmd->opcode == CHANGE_DEFINITION) {
283: printf("CHANGE_DEF ");
284: } else if (xs->cmd->opcode == MODE_SENSE_BIG) {
285: printf("MODE_SENSE_BIG ");
286: } else if (xs->cmd->opcode == MODE_SELECT_BIG) {
287: printf("MODE_SELECT_BIG ");
288: } else if (xs->cmd->opcode == 0x25) {
289: printf("READ_CAPACITY ");
290: } else if (xs->cmd->opcode == 0x08) {
291: printf("READ_COMMAND ");
292: }
293: #endif
294: if (flags & SCSI_POLL) {
295: cqep = mc;
296: iopb = miopb;
297: } else {
298: cqep = vs_getcqe(sc);
299: if (cqep == NULL) {
300: return (TRY_AGAIN_LATER);
301: }
302: iopb = vs_getiopb(sc);
303: }
304:
305: /* s = splbio();*/
306: iopb_len = sizeof(M328_short_IOPB) + xs->cmdlen;
307: szero(iopb, sizeof(M328_IOPB));
308:
309: scopy(xs->cmd, &iopb->iopb_SCSI[0], xs->cmdlen);
310: iopb->iopb_CMD = IOPB_SCSI;
311: #if 0
312: LV(iopb->iopb_BUFF, kvtop(xs->data));
313: LV(iopb->iopb_LENGTH, xs->datalen);
314: #endif
315: iopb->iopb_UNIT = slp->lun << 3;
316: iopb->iopb_UNIT |= slp->target;
317: iopb->iopb_NVCT = (u_char)sc->sc_nvec;
318: iopb->iopb_EVCT = (u_char)sc->sc_evec;
319:
320: /*
321: * Since the 88k's don't support cache snooping, we have
322: * to flush the cache for a write and flush with inval for
323: * a read, prior to starting the IO.
324: */
325: if (xs->flags & SCSI_DATA_IN) { /* read */
326: #if defined(mvme88k)
327: dma_cachectl(xs->data, xs->datalen,
328: DMA_CACHE_SYNC_INVAL);
329: #endif
330: iopb->iopb_OPTION |= OPT_READ;
331: } else { /* write */
332: #if defined(mvme88k)
333: dma_cachectl(xs->data, xs->datalen,
334: DMA_CACHE_SYNC);
335: #endif
336: iopb->iopb_OPTION |= OPT_WRITE;
337: }
338:
339: if (flags & SCSI_POLL) {
340: iopb->iopb_OPTION |= OPT_INTDIS;
341: iopb->iopb_LEVEL = 0;
342: } else {
343: iopb->iopb_OPTION |= OPT_INTEN;
344: iopb->iopb_LEVEL = sc->sc_ipl;
345: }
346: iopb->iopb_ADDR = ADDR_MOD;
347:
348: /*
349: * Wait until we can use the command queue entry.
350: * Should only have to wait if the master command
351: * queue entry is busy.
352: */
353: while (cqep->cqe_QECR & M_QECR_GO);
354:
355: cqep->cqe_IOPB_ADDR = OFF(iopb);
356: cqep->cqe_IOPB_LENGTH = iopb_len;
357: if (flags & SCSI_POLL) {
358: cqep->cqe_WORK_QUEUE = slp->target + 1;
359: } else {
360: cqep->cqe_WORK_QUEUE = slp->target + 1;
361: }
362:
363: MALLOC(m328_cmd, M328_CMD*, sizeof(M328_CMD), M_DEVBUF, M_WAITOK);
364:
365: m328_cmd->xs = xs;
366: if (xs->datalen) {
367: m328_cmd->top_sg_list = vs_build_memory_structure(xs, iopb);
368: } else {
369: m328_cmd->top_sg_list = (M328_SG)0;
370: }
371:
372: LV(cqep->cqe_CTAG, m328_cmd);
373:
374: if (crb->crb_CRSW & M_CRSW_AQ) {
375: cqep->cqe_QECR = M_QECR_AA;
376: }
377: VL(buf, iopb->iopb_BUFF);
378: VL(len, iopb->iopb_LENGTH);
379: #ifdef SDEBUG
380: printf("tgt %d lun %d buf %x len %d wqn %d ipl %d\n", slp->target,
381: slp->lun, buf, len, cqep->cqe_WORK_QUEUE, iopb->iopb_LEVEL);
382: #endif
383: cqep->cqe_QECR |= M_QECR_GO;
384:
385: if (flags & SCSI_POLL) {
386: /* poll for the command to complete */
387: /*splx(s);*/
388: vs_poll(sc, xs);
389: return (COMPLETE);
390: }
391: /*splx(s);*/
392: return (SUCCESSFULLY_QUEUED);
393: }
394:
395: void
396: vs_chksense(xs)
397: struct scsi_xfer *xs;
398: {
399: int s;
400: struct scsi_link *slp = xs->sc_link;
401: struct vs_softc *sc = slp->adapter_softc;
402: struct scsi_sense *ss;
403: M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE;
404: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
405: M328_IOPB *miopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB;
406:
407: /* ack and clear the error */
408: CRB_CLR_DONE(CRSW);
409: CRB_CLR_ER(CRSW);
410: xs->status = 0;
411:
412: szero(miopb, sizeof(M328_IOPB));
413: /* This is a command, so point to it */
414: ss = (void *)&miopb->iopb_SCSI[0];
415: szero(ss, sizeof(*ss));
416: ss->opcode = REQUEST_SENSE;
417: ss->byte2 = slp->lun << 5;
418: ss->length = sizeof(struct scsi_sense_data);
419:
420: miopb->iopb_CMD = IOPB_SCSI;
421: miopb->iopb_OPTION = OPT_READ;
422: miopb->iopb_NVCT = (u_char)sc->sc_nvec;
423: miopb->iopb_EVCT = (u_char)sc->sc_evec;
424: miopb->iopb_LEVEL = 0; /*sc->sc_ipl;*/
425: miopb->iopb_ADDR = ADDR_MOD;
426: LV(miopb->iopb_BUFF, kvtop((vaddr_t)&xs->sense));
427: LV(miopb->iopb_LENGTH, sizeof(struct scsi_sense_data));
428:
429: szero(mc, sizeof(M328_CQE));
430: mc->cqe_IOPB_ADDR = OFF(miopb);
431: mc->cqe_IOPB_LENGTH = sizeof(M328_short_IOPB) +
432: sizeof(struct scsi_sense);
433: mc->cqe_WORK_QUEUE = 0;
434: mc->cqe_QECR = M_QECR_GO;
435: /* poll for the command to complete */
436: s = splbio();
437: do_vspoll(sc, 0, 1);
438: /*
439: if (xs->cmd->opcode != PREVENT_ALLOW) {
440: xs->error = XS_SENSE;
441: }
442: */
443: xs->status = riopb->iopb_STATUS >> 8;
444: #ifdef SDEBUG
445: scsi_print_sense(xs);
446: #endif
447: splx(s);
448: }
449:
450: M328_CQE *
451: vs_getcqe(sc)
452: struct vs_softc *sc;
453: {
454: M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB;
455: M328_CQE *cqep;
456:
457: cqep = (M328_CQE *)&sc->sc_vsreg->sh_CQE[mcsb->mcsb_QHDP];
458:
459: if (cqep->cqe_QECR & M_QECR_GO)
460: return NULL; /* Hopefully, this will never happen */
461: mcsb->mcsb_QHDP++;
462: if (mcsb->mcsb_QHDP == NUM_CQE) mcsb->mcsb_QHDP = 0;
463: szero(cqep, sizeof(M328_CQE));
464: return cqep;
465: }
466:
467: M328_IOPB *
468: vs_getiopb(sc)
469: struct vs_softc *sc;
470: {
471: M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB;
472: M328_IOPB *iopb;
473: int slot;
474:
475: if (mcsb->mcsb_QHDP == 0) {
476: slot = NUM_CQE - 1;
477: } else {
478: slot = mcsb->mcsb_QHDP - 1;
479: }
480: iopb = (M328_IOPB *)&sc->sc_vsreg->sh_IOPB[slot];
481: szero(iopb, sizeof(M328_IOPB));
482: return iopb;
483: }
484:
485: void
486: vs_initialize(sc)
487: struct vs_softc *sc;
488: {
489: M328_CIB *cib = (M328_CIB *)&sc->sc_vsreg->sh_CIB;
490: M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE;
491: M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB;
492: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
493: M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB;
494: M328_IOPB *iopb;
495: M328_WQCF *wiopb = (M328_WQCF *)&sc->sc_vsreg->sh_MCE_IOPB;
496: u_short i, crsw;
497: int failed = 0;
498:
499: CRB_CLR_DONE(CRSW);
500: szero(cib, sizeof(M328_CIB));
501: mcsb->mcsb_QHDP = 0;
502: sc->sc_qhp = 0;
503: cib->cib_NCQE = 10;
504: cib->cib_BURST = 0;
505: cib->cib_NVECT = sc->sc_ipl << 8;
506: cib->cib_NVECT |= sc->sc_nvec;
507: cib->cib_EVECT = sc->sc_ipl << 8;
508: cib->cib_EVECT |= sc->sc_evec;
509: cib->cib_PID = 0x07;
510: cib->cib_SID = 0x00;
511: cib->cib_CRBO = OFF(crb);
512: cib->cib_SELECT_msw = HI(SELECTION_TIMEOUT);
513: cib->cib_SELECT_lsw = LO(SELECTION_TIMEOUT);
514: cib->cib_WQ0TIMO_msw = HI(4);
515: cib->cib_WQ0TIMO_lsw = LO(4);
516: cib->cib_VMETIMO_msw = 0; /*HI(VME_BUS_TIMEOUT);*/
517: cib->cib_VMETIMO_lsw = 0; /*LO(VME_BUS_TIMEOUT);*/
518: cib->cib_SBRIV = sc->sc_ipl << 8;
519: cib->cib_SBRIV |= sc->sc_evec;
520: cib->cib_SOF0 = 0x15;
521: cib->cib_SRATE0 = 100/4;
522: cib->cib_SOF1 = 0x0;
523: cib->cib_SRATE1 = 0x0;
524:
525: iopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB;
526: szero(iopb, sizeof(M328_IOPB));
527: iopb->iopb_CMD = CNTR_INIT;
528: iopb->iopb_OPTION = 0;
529: iopb->iopb_NVCT = (u_char)sc->sc_nvec;
530: iopb->iopb_EVCT = (u_char)sc->sc_evec;
531: iopb->iopb_LEVEL = 0; /*sc->sc_ipl;*/
532: iopb->iopb_ADDR = SHIO_MOD;
533: LV(iopb->iopb_BUFF, OFF(cib));
534: LV(iopb->iopb_LENGTH, sizeof(M328_CIB));
535:
536: szero(mc, sizeof(M328_CQE));
537: mc->cqe_IOPB_ADDR = OFF(iopb);
538: mc->cqe_IOPB_LENGTH = sizeof(M328_IOPB);
539: mc->cqe_WORK_QUEUE = 0;
540: mc->cqe_QECR = M_QECR_GO;
541: /* poll for the command to complete */
542: do_vspoll(sc, 0, 1);
543: CRB_CLR_DONE(CRSW);
544:
545: /* initialize work queues */
546: for (i=1; i<8; i++) {
547: szero(wiopb, sizeof(M328_IOPB));
548: wiopb->wqcf_CMD = CNTR_INIT_WORKQ;
549: wiopb->wqcf_OPTION = 0;
550: wiopb->wqcf_NVCT = (u_char)sc->sc_nvec;
551: wiopb->wqcf_EVCT = (u_char)sc->sc_evec;
552: wiopb->wqcf_ILVL = 0; /*sc->sc_ipl;*/
553: wiopb->wqcf_WORKQ = i;
554: wiopb->wqcf_WOPT = (WQO_FOE | WQO_INIT);
555: wiopb->wqcf_SLOTS = JAGUAR_MAX_Q_SIZ;
556: LV(wiopb->wqcf_CMDTO, 2);
557:
558: szero(mc, sizeof(M328_CQE));
559: mc->cqe_IOPB_ADDR = OFF(wiopb);
560: mc->cqe_IOPB_LENGTH = sizeof(M328_IOPB);
561: mc->cqe_WORK_QUEUE = 0;
562: mc->cqe_QECR = M_QECR_GO;
563: /* poll for the command to complete */
564: do_vspoll(sc, 0, 1);
565: if (CRSW & M_CRSW_ER) {
566: /*printf("\nerror: queue %d status = 0x%x\n",
567: i, riopb->iopb_STATUS);*/
568: /*failed = 1;*/
569: CRB_CLR_ER(CRSW);
570: }
571: CRB_CLR_DONE(CRSW);
572: delay(500);
573: }
574: /* start queue mode */
575: CRSW = 0;
576: mcsb->mcsb_MCR |= M_MCR_SQM;
577: crsw = CRSW;
578: do_vspoll(sc, 0, 1);
579: if (CRSW & M_CRSW_ER) {
580: printf("error: status = 0x%x\n", riopb->iopb_STATUS);
581: CRB_CLR_ER(CRSW);
582: }
583: CRB_CLR_DONE(CRSW);
584:
585: if (failed) {
586: printf(": failed!\n");
587: return;
588: }
589: /* reset SCSI bus */
590: vs_reset(sc);
591: /* sync all devices */
592: vs_resync(sc);
593: printf(": target %d\n", sc->sc_link.adapter_target);
594: }
595:
596: void
597: vs_resync(sc)
598: struct vs_softc *sc;
599: {
600: M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE;
601: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
602: M328_DRCF *devreset = (M328_DRCF *)&sc->sc_vsreg->sh_MCE_IOPB;
603: u_short i;
604:
605: for (i=0; i<7; i++) {
606: szero(devreset, sizeof(M328_DRCF));
607: devreset->drcf_CMD = CNTR_DEV_REINIT;
608: devreset->drcf_OPTION = 0x00; /* no interrupts yet... */
609: devreset->drcf_NVCT = sc->sc_nvec;
610: devreset->drcf_EVCT = sc->sc_evec;
611: devreset->drcf_ILVL = 0;
612: devreset->drcf_UNIT = i;
613:
614: szero(mc, sizeof(M328_CQE));
615: mc->cqe_IOPB_ADDR = OFF(devreset);
616: mc->cqe_IOPB_LENGTH = sizeof(M328_DRCF);
617: mc->cqe_WORK_QUEUE = 0;
618: mc->cqe_QECR = M_QECR_GO;
619: /* poll for the command to complete */
620: do_vspoll(sc, 0, 0);
621: if (riopb->iopb_STATUS) {
622: sc->sc_tinfo[i].avail = 0;
623: } else {
624: sc->sc_tinfo[i].avail = 1;
625: }
626: if (CRSW & M_CRSW_ER) {
627: CRB_CLR_ER(CRSW);
628: }
629: CRB_CLR_DONE(CRSW);
630: }
631: }
632:
633: void
634: vs_reset(sc)
635: struct vs_softc *sc;
636: {
637: u_int s;
638: M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE;
639: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
640: M328_SRCF *reset = (M328_SRCF *)&sc->sc_vsreg->sh_MCE_IOPB;
641:
642: szero(reset, sizeof(M328_SRCF));
643: reset->srcf_CMD = IOPB_RESET;
644: reset->srcf_OPTION = 0x00; /* no interrupts yet... */
645: reset->srcf_NVCT = sc->sc_nvec;
646: reset->srcf_EVCT = sc->sc_evec;
647: reset->srcf_ILVL = 0;
648: reset->srcf_BUSID = 0;
649: s = splbio();
650:
651: szero(mc, sizeof(M328_CQE));
652: mc->cqe_IOPB_ADDR = OFF(reset);
653: mc->cqe_IOPB_LENGTH = sizeof(M328_SRCF);
654: mc->cqe_WORK_QUEUE = 0;
655: mc->cqe_QECR = M_QECR_GO;
656: /* poll for the command to complete */
657: for (;;) {
658: do_vspoll(sc, 0, 0);
659: /* ack & clear scsi error condition cause by reset */
660: if (CRSW & M_CRSW_ER) {
661: CRB_CLR_ER(CRSW);
662: CRB_CLR_DONE(CRSW);
663: riopb->iopb_STATUS = 0;
664: break;
665: }
666: CRB_CLR_DONE(CRSW);
667: }
668: /* thaw all work queues */
669: thaw_queue(sc, 0xFF);
670: splx(s);
671: }
672:
673: /*
674: * Process an interrupt from the MVME328
675: * We'll generally update: xs->{flags,resid,error,sense,status} and
676: * occasionally xs->retries.
677: */
678:
679: int
680: vs_checkintr(sc, xs, status)
681: struct vs_softc *sc;
682: struct scsi_xfer *xs;
683: int *status;
684: {
685: int target = -1;
686: int lun = -1;
687: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
688: struct scsi_generic *cmd;
689: u_long buf;
690: u_long len;
691: u_char error;
692:
693: target = xs->sc_link->target;
694: lun = xs->sc_link->lun;
695: cmd = (struct scsi_generic *)&riopb->iopb_SCSI[0];
696:
697: VL(buf, riopb->iopb_BUFF);
698: VL(len, riopb->iopb_LENGTH);
699: *status = riopb->iopb_STATUS >> 8;
700: error = riopb->iopb_STATUS & 0xFF;
701:
702: #ifdef SDEBUG
703: printf("scsi_chk() ");
704:
705: if (xs->cmd->opcode == 0) {
706: printf("TEST_UNIT_READY ");
707: } else if (xs->cmd->opcode == REQUEST_SENSE) {
708: printf("REQUEST_SENSE ");
709: } else if (xs->cmd->opcode == INQUIRY) {
710: printf("INQUIRY ");
711: } else if (xs->cmd->opcode == MODE_SELECT) {
712: printf("MODE_SELECT ");
713: } else if (xs->cmd->opcode == MODE_SENSE) {
714: printf("MODE_SENSE ");
715: } else if (xs->cmd->opcode == START_STOP) {
716: printf("START_STOP ");
717: } else if (xs->cmd->opcode == RESERVE) {
718: printf("RESERVE ");
719: } else if (xs->cmd->opcode == RELEASE) {
720: printf("RELEASE ");
721: } else if (xs->cmd->opcode == PREVENT_ALLOW) {
722: printf("PREVENT_ALLOW ");
723: } else if (xs->cmd->opcode == POSITION_TO_ELEMENT) {
724: printf("POSITION_TO_EL ");
725: } else if (xs->cmd->opcode == CHANGE_DEFINITION) {
726: printf("CHANGE_DEF ");
727: } else if (xs->cmd->opcode == MODE_SENSE_BIG) {
728: printf("MODE_SENSE_BIG ");
729: } else if (xs->cmd->opcode == MODE_SELECT_BIG) {
730: printf("MODE_SELECT_BIG ");
731: } else if (xs->cmd->opcode == 0x25) {
732: printf("READ_CAPACITY ");
733: } else if (xs->cmd->opcode == 0x08) {
734: printf("READ_COMMAND ");
735: }
736:
737: printf("tgt %d lun %d buf %x len %d status %x ",
738: target, lun, buf, len, riopb->iopb_STATUS);
739:
740: if (CRSW & M_CRSW_EX) {
741: printf("[ex]");
742: }
743: if (CRSW & M_CRSW_QMS) {
744: printf("[qms]");
745: }
746: if (CRSW & M_CRSW_SC) {
747: printf("[sc]");
748: }
749: if (CRSW & M_CRSW_SE) {
750: printf("[se]");
751: }
752: if (CRSW & M_CRSW_AQ) {
753: printf("[aq]");
754: }
755: if (CRSW & M_CRSW_ER) {
756: printf("[er]");
757: }
758: printf("\n");
759: #endif
760: if (len != xs->datalen) {
761: xs->resid = xs->datalen - len;
762: } else {
763: xs->resid = 0;
764: }
765:
766: if (error == SCSI_SELECTION_TO) {
767: xs->error = XS_SELTIMEOUT;
768: xs->status = -1;
769: *status = -1;
770: }
771: return 1;
772: }
773:
774: void
775: vs_intr(arg)
776: void *arg;
777: {
778: struct vs_softc *sc = (struct vs_softc *)arg;
779: M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB;
780: struct scsi_xfer *xs;
781: M328_CMD *m328_cmd;
782: unsigned long loc;
783: int status;
784: int s;
785:
786: s = splbio();
787: /* Got a valid interrupt on this device */
788:
789: VL(loc, crb->crb_CTAG);
790: #ifdef SDEBUG
791: printf("Interrupt!!! ");
792: printf("loc == 0x%x\n", loc);
793: #endif
794: /*
795: * If this is a controller error, there won't be a m328_cmd
796: * pointer in the CTAG field. Bad things happen if you try
797: * to point to address 0. Controller error should be handled
798: * in vsdma.c I'll change this soon - steve.
799: */
800: if (loc) {
801: m328_cmd = (M328_CMD *)loc;
802: xs = m328_cmd->xs;
803: if (m328_cmd->top_sg_list) {
804: vs_dealloc_scatter_gather(m328_cmd->top_sg_list);
805: m328_cmd->top_sg_list = (M328_SG)0;
806: }
807:
808: FREE(m328_cmd, M_DEVBUF); /* free the command tag */
809: if (vs_checkintr (sc, xs, &status)) {
810: vs_scsidone(xs, status);
811: }
812: }
813: splx(s);
814: }
815:
816: /*
817: * Useful functions for scatter/gather list
818: */
819:
820: M328_SG
821: vs_alloc_scatter_gather()
822: {
823: M328_SG sg;
824:
825: MALLOC(sg, M328_SG, sizeof(struct m328_sg), M_DEVBUF, M_WAITOK);
826: bzero(sg, sizeof(struct m328_sg));
827:
828: return (sg);
829: }
830:
831: void
832: vs_dealloc_scatter_gather(sg)
833: M328_SG sg;
834: {
835: int i;
836:
837: if (sg->level > 0) {
838: for (i = 0; sg->down[i] && i<MAX_SG_ELEMENTS; i++) {
839: vs_dealloc_scatter_gather(sg->down[i]);
840: }
841: }
842: FREE(sg, M_DEVBUF);
843: }
844:
845: void
846: vs_link_sg_element(element, phys_add, len)
847: sg_list_element_t *element;
848: vaddr_t phys_add;
849: int len;
850: {
851:
852: element->count.bytes = len;
853: LV(element->address, phys_add);
854: element->link = 0; /* FALSE */
855: element->transfer_type = NORMAL_TYPE;
856: element->memory_type = LONG_TRANSFER;
857: element->address_modifier = 0xD;
858: }
859:
860: void
861: vs_link_sg_list(list, phys_add, elements)
862: sg_list_element_t *list;
863: vaddr_t phys_add;
864: int elements;
865: {
866:
867: list->count.scatter.gather = elements;
868: LV(list->address, phys_add);
869: list->link = 1; /* TRUE */
870: list->transfer_type = NORMAL_TYPE;
871: list->memory_type = LONG_TRANSFER;
872: list->address_modifier = 0xD;
873: }
874:
875: M328_SG
876: vs_build_memory_structure(xs, iopb)
877: struct scsi_xfer *xs;
878: M328_IOPB *iopb; /* the iopb */
879: {
880: M328_SG sg;
881: vaddr_t starting_point_virt, point_virt, virt;
882: paddr_t starting_point_phys, point1_phys, point2_phys;
883: u_int len;
884: int level;
885:
886: sg = (M328_SG)0; /* Hopefully we need no scatter/gather list */
887:
888: /*
889: * We have the following things:
890: * virt the virtual address of the contiguous virtual
891: * memory block
892: * len the length of the contiguous virtual memory
893: * block
894: * starting_point_virt the virtual address of the contiguous
895: * *physical* memory block
896: * starting_point_phys the *physical* address of the contiguous
897: * *physical* memory block
898: * point_virt the pointer to the virtual memory we are
899: * checking at the moment
900: * point1_phys the pointer to the *physical* memory we are
901: * checking at the moment
902: * point2_phys the pointer to the *physical* memory we are
903: * checking at the moment
904: */
905:
906: level = 0;
907: virt = starting_point_virt = (vaddr_t)xs->data;
908: point1_phys = starting_point_phys = kvtop((vaddr_t)xs->data);
909: len = xs->datalen;
910:
911: /*
912: * Check if we need scatter/gather
913: */
914: if (len > PAGE_SIZE) {
915: for (level = 0, point_virt = round_page(starting_point_virt+1);
916: /* if we do already scatter/gather we have to stay in
917: the loop and jump */
918: point_virt < virt + (vaddr_t)len || sg;
919: point_virt += PAGE_SIZE) { /* out later */
920:
921: point2_phys = kvtop(point_virt);
922:
923: if ((point2_phys - trunc_page(point1_phys) - PAGE_SIZE) ||
924: /* physical memory is not contiguous */
925: (point_virt - starting_point_virt >=
926: MAX_SG_BLOCK_SIZE && sg)) {
927: /* we only can access (1<<16)-1 bytes in
928: scatter/gather_mode */
929: if (point_virt - starting_point_virt >=
930: MAX_SG_BLOCK_SIZE) {
931: /* We were walking too far for one
932: scatter/gather block ... */
933: assert( MAX_SG_BLOCK_SIZE > PAGE_SIZE );
934: point_virt =
935: trunc_page(starting_point_virt +
936: MAX_SG_BLOCK_SIZE-1);
937: /* So go back to the beginning of the
938: last matching page and generate the
939: physical address of this location
940: for the next time. */
941: point2_phys = kvtop(point_virt);
942: }
943:
944: if (!sg) {
945: /* We allocate our fist scatter/gather
946: list */
947: sg = vs_alloc_scatter_gather();
948: }
949: #if 1 /* broken firmware */
950: if (sg->elements >= MAX_SG_ELEMENTS) {
951: vs_dealloc_scatter_gather(sg);
952: return (NULL);
953: }
954: #else /* if the firmware will ever get fixed */
955: while (sg->elements >= MAX_SG_ELEMENTS) {
956: /* If the list full in this layer ? */
957: if (!sg->up) {
958: sg->up =
959: vs_alloc_scatter_gather();
960: sg->up->level = sg->level+1;
961: sg->up->down[0] = sg;
962: sg->up->elements = 1;
963: }
964: /* link this full list also in physical
965: memory */
966: vs_link_sg_list(
967: &(sg->up->list[
968: sg->up->elements - 1]),
969: kvtop((vaddr_t)sg->list),
970: sg->elements);
971: sg = sg->up; /* Climb up */
972: }
973: /* As long as we are not a the base level */
974: while (sg->level) {
975: int i;
976:
977: i = sg->elements;
978: /* We need a new element */
979: sg->down[i] =
980: vs_alloc_scatter_gather();
981: sg->down[i]->level = sg->level - 1;
982: sg->down[i]->up = sg;
983: sg->elements++;
984: sg = sg->down[i]; /* Climb down */
985: }
986: #endif /* 1 */
987:
988: if (point_virt < virt+(vaddr_t)len) {
989: /* linking element */
990: vs_link_sg_element(
991: &(sg->list[sg->elements]),
992: starting_point_phys,
993: point_virt-starting_point_virt);
994: sg->elements++;
995: } else {
996: /* linking last element */
997: vs_link_sg_element(
998: &(sg->list[sg->elements]),
999: starting_point_phys,
1000: (vaddr_t)(virt + len) -
1001: starting_point_virt);
1002: sg->elements++;
1003: break;
1004: /* We have now collected all blocks */
1005: }
1006: starting_point_virt = point_virt;
1007: starting_point_phys = point2_phys;
1008: }
1009: point1_phys = point2_phys;
1010: }
1011: }
1012:
1013: /*
1014: * Climb up along the right side of the tree until we reach the top.
1015: */
1016:
1017: if (sg) {
1018: while (sg->up) {
1019: /* link this list also in physical memory */
1020: vs_link_sg_list(&(sg->up->list[sg->up->elements-1]),
1021: kvtop((vaddr_t)sg->list), sg->elements);
1022: sg = sg->up; /* Climb up */
1023: }
1024:
1025: iopb->iopb_OPTION |= M_OPT_SG;
1026: iopb->iopb_ADDR |= M_ADR_SG_LINK;
1027: LV(iopb->iopb_BUFF, kvtop((vaddr_t)sg->list));
1028: LV(iopb->iopb_LENGTH, sg->elements);
1029: LV(iopb->iopb_SGTTL, len);
1030: } else {
1031: /* no scatter/gather necessary */
1032: LV(iopb->iopb_BUFF, starting_point_phys);
1033: LV(iopb->iopb_LENGTH, len);
1034: }
1035: return (sg);
1036: }
CVSweb