Annotation of sys/arch/vax/mscp/mscp.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: mscp.c,v 1.9 2005/11/24 04:53:56 brad Exp $ */
2: /* $NetBSD: mscp.c,v 1.16 2001/11/13 07:38:28 lukem Exp $ */
3:
4: /*
5: * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
6: * Copyright (c) 1988 Regents of the University of California.
7: * All rights reserved.
8: *
9: * This code is derived from software contributed to Berkeley by
10: * Chris Torek.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)mscp.c 7.5 (Berkeley) 12/16/90
37: */
38:
39: /*
40: * MSCP generic driver routines
41: */
42:
43: #include <sys/cdefs.h>
44:
45: #include <sys/param.h>
46: #include <sys/buf.h>
47: #include <sys/malloc.h>
48: #include <sys/device.h>
49: #include <sys/proc.h>
50: #include <sys/systm.h>
51:
52: #include <machine/bus.h>
53:
54: #include <arch/vax/mscp/mscp.h>
55: #include <arch/vax/mscp/mscpreg.h>
56: #include <arch/vax/mscp/mscpvar.h>
57:
58: #define PCMD PSWP /* priority for command packet waits */
59:
60: /*
61: * Get a command packet. Second argument is true iff we are
62: * to wait if necessary. Return NULL if none are available and
63: * we cannot wait.
64: */
65: struct mscp *
66: mscp_getcp(mi, canwait)
67: struct mscp_softc *mi;
68: int canwait;
69: {
70: #define mri (&mi->mi_cmd)
71: struct mscp *mp;
72: int i;
73: int s = splbio();
74:
75: again:
76: /*
77: * Ensure that we have some command credits, and
78: * that the next command packet is free.
79: */
80: if (mi->mi_credits <= MSCP_MINCREDITS) {
81: if (!canwait) {
82: splx(s);
83: return (NULL);
84: }
85: mi->mi_wantcredits = 1;
86: (void) tsleep(&mi->mi_wantcredits, PCMD, "mscpwcrd", 0);
87: goto again;
88: }
89: i = mri->mri_next;
90: if (mri->mri_desc[i] & MSCP_OWN) {
91: if (!canwait) {
92: splx(s);
93: return (NULL);
94: }
95: mi->mi_wantcmd = 1;
96: (void) tsleep(&mi->mi_wantcmd, PCMD, "mscpwcmd", 0);
97: goto again;
98: }
99: mi->mi_credits--;
100: mri->mri_desc[i] &= ~MSCP_INT;
101: mri->mri_next = (mri->mri_next + 1) % mri->mri_size;
102: splx(s);
103: mp = &mri->mri_ring[i];
104:
105: /*
106: * Initialise some often-zero fields.
107: * ARE THE LAST TWO NECESSARY IN GENERAL? IT SURE WOULD BE
108: * NICE IF DEC SOLD DOCUMENTATION FOR THEIR OWN CONTROLLERS.
109: */
110: mp->mscp_msglen = MSCP_MSGLEN;
111: mp->mscp_flags = 0;
112: mp->mscp_modifier = 0;
113: mp->mscp_seq.seq_bytecount = 0;
114: mp->mscp_seq.seq_buffer = 0;
115: mp->mscp_seq.seq_mapbase = 0;
116: /*???*/ mp->mscp_sccc.sccc_errlgfl = 0;
117: /*???*/ mp->mscp_sccc.sccc_copyspd = 0;
118: return (mp);
119: #undef mri
120: }
121:
122: #ifdef AVOID_EMULEX_BUG
123: int mscp_aeb_xor = 0x8000bb80;
124: #endif
125:
126: /*
127: * Handle a response ring transition.
128: */
129: void
130: mscp_dorsp(mi)
131: struct mscp_softc *mi;
132: {
133: struct device *drive;
134: struct mscp_device *me = mi->mi_me;
135: struct mscp_ctlr *mc = mi->mi_mc;
136: struct buf *bp;
137: struct mscp *mp;
138: struct mscp_xi *mxi;
139: int nextrsp;
140: int st, error;
141: extern int cold;
142: extern struct mscp slavereply;
143:
144: nextrsp = mi->mi_rsp.mri_next;
145: loop:
146: if (mi->mi_rsp.mri_desc[nextrsp] & MSCP_OWN) {
147: /*
148: * No more responses. Remember the next expected
149: * response index. Check to see if we have some
150: * credits back, and wake up sleepers if so.
151: */
152: mi->mi_rsp.mri_next = nextrsp;
153: if (mi->mi_wantcredits && mi->mi_credits > MSCP_MINCREDITS) {
154: mi->mi_wantcredits = 0;
155: wakeup((caddr_t) &mi->mi_wantcredits);
156: }
157: return;
158: }
159:
160: mp = &mi->mi_rsp.mri_ring[nextrsp];
161: mi->mi_credits += MSCP_CREDITS(mp->mscp_msgtc);
162: /*
163: * Controllers are allowed to interrupt as any drive, so we
164: * must check the command before checking for a drive.
165: */
166: if (mp->mscp_opcode == (M_OP_SETCTLRC | M_OP_END)) {
167: if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS) {
168: mi->mi_flags |= MSC_READY;
169: } else {
170: printf("%s: SETCTLRC failed: %d ",
171: mi->mi_dev.dv_xname, mp->mscp_status);
172: mscp_printevent(mp);
173: }
174: goto done;
175: }
176:
177: /*
178: * Found a response. Update credit information. If there is
179: * nothing else to do, jump to `done' to get the next response.
180: */
181: if (mp->mscp_unit >= mi->mi_driveno) { /* Must expand drive table */
182: int tmpno = ((mp->mscp_unit + 32) & 0xffe0) * sizeof(void *);
183: struct device **tmp = (struct device **)
184: malloc(tmpno, M_DEVBUF, M_NOWAIT);
185: if (tmp == NULL)
186: panic("mscp_dorsp");
187: bzero(tmp, tmpno);
188: if (mi->mi_driveno) {
189: bcopy(mi->mi_dp, tmp, mi->mi_driveno);
190: free(mi->mi_dp, mi->mi_driveno);
191: }
192: mi->mi_driveno = tmpno;
193: mi->mi_dp = tmp;
194: }
195:
196: drive = mi->mi_dp[mp->mscp_unit];
197:
198: switch (MSCP_MSGTYPE(mp->mscp_msgtc)) {
199:
200: case MSCPT_SEQ:
201: break;
202:
203: case MSCPT_DATAGRAM:
204: (*me->me_dgram)(drive, mp, mi);
205: goto done;
206:
207: case MSCPT_CREDITS:
208: goto done;
209:
210: case MSCPT_MAINTENANCE:
211: default:
212: printf("%s: unit %d: unknown message type 0x%x ignored\n",
213: mi->mi_dev.dv_xname, mp->mscp_unit,
214: MSCP_MSGTYPE(mp->mscp_msgtc));
215: goto done;
216: }
217:
218: /*
219: * Handle individual responses.
220: */
221: st = mp->mscp_status & M_ST_MASK;
222: error = 0;
223: switch (mp->mscp_opcode) {
224:
225: case M_OP_END:
226: /*
227: * The controller presents a bogus END packet when
228: * a read/write command is given with an illegal
229: * block number. This is contrary to the MSCP
230: * specification (ENDs are to be given only for
231: * invalid commands), but that is the way of it.
232: */
233: if (st == M_ST_INVALCMD && mp->mscp_cmdref != 0) {
234: printf("%s: bad lbn (%d)?\n", drive->dv_xname,
235: (int)mp->mscp_seq.seq_lbn);
236: error = EIO;
237: goto rwend;
238: }
239: goto unknown;
240:
241: case M_OP_ONLINE | M_OP_END:
242: /*
243: * Finished an ON LINE request. Call the driver to
244: * find out whether it succeeded. If so, mark it on
245: * line.
246: */
247: (*me->me_online)(drive, mp);
248: break;
249:
250: case M_OP_GETUNITST | M_OP_END:
251: /*
252: * Got unit status. If we are autoconfiguring, save
253: * the mscp struct so that mscp_attach know what to do.
254: * If the drive isn't configured, call config_found()
255: * to set it up, otherwise it's just a "normal" unit
256: * status.
257: */
258: if (cold)
259: bcopy(mp, &slavereply, sizeof(struct mscp));
260:
261: if (mp->mscp_status == (M_ST_OFFLINE|M_OFFLINE_UNKNOWN))
262: break;
263:
264: if (drive == 0) {
265: struct drive_attach_args da;
266:
267: da.da_mp = (struct mscp *)mp;
268: da.da_typ = mi->mi_type;
269: config_found(&mi->mi_dev, (void *)&da, mscp_print);
270: } else
271: /* Hack to avoid complaints */
272: if (!(((mp->mscp_event & M_ST_MASK) == M_ST_AVAILABLE)
273: && cold))
274: (*me->me_gotstatus)(drive, mp);
275: break;
276:
277: case M_OP_AVAILATTN:
278: /*
279: * The drive went offline and we did not notice.
280: * Mark it off line now, to force an on line request
281: * next, so we can make sure it is still the same
282: * drive.
283: *
284: * IF THE UDA DRIVER HAS A COMMAND AWAITING UNIBUS
285: * RESOURCES, THAT COMMAND MAY GO OUT BEFORE THE ON
286: * LINE. IS IT WORTH FIXING??
287: */
288: #ifdef notyet
289: (*md->md_offline)(ui, mp);
290: #endif
291: break;
292:
293: case M_OP_POS | M_OP_END:
294: case M_OP_WRITM | M_OP_END:
295: case M_OP_AVAILABLE | M_OP_END:
296: /*
297: * A non-data transfer operation completed.
298: */
299: (*me->me_cmddone)(drive, mp);
300: break;
301:
302: case M_OP_READ | M_OP_END:
303: case M_OP_WRITE | M_OP_END:
304: /*
305: * A transfer finished. Get the buffer, and release its
306: * map registers via ubadone(). If the command finished
307: * with an off line or available status, the drive went
308: * off line (the idiot controller does not tell us until
309: * it comes back *on* line, or until we try to use it).
310: */
311: rwend:
312: #ifdef DIAGNOSTIC
313: if (mp->mscp_cmdref >= NCMD) {
314: /*
315: * No buffer means there is a bug somewhere!
316: */
317: printf("%s: io done, but bad xfer number?\n",
318: drive->dv_xname);
319: mscp_hexdump(mp);
320: break;
321: }
322: #endif
323:
324: if (mp->mscp_cmdref == -1) {
325: (*me->me_cmddone)(drive, mp);
326: break;
327: }
328: mxi = &mi->mi_xi[mp->mscp_cmdref];
329: if (mxi->mxi_inuse == 0)
330: panic("mxi not inuse");
331: bp = mxi->mxi_bp;
332: /*
333: * Mark any error-due-to-bad-LBN (via `goto rwend').
334: * WHAT STATUS WILL THESE HAVE? IT SURE WOULD BE NICE
335: * IF DEC SOLD DOCUMENTATION FOR THEIR OWN CONTROLLERS.
336: */
337: if (error) {
338: bp->b_flags |= B_ERROR;
339: bp->b_error = error;
340: }
341: if (st == M_ST_OFFLINE || st == M_ST_AVAILABLE) {
342: #ifdef notyet
343: (*md->md_offline)(ui, mp);
344: #endif
345: }
346:
347: /*
348: * If the transfer has something to do with bad
349: * block forwarding, let the driver handle the
350: * rest.
351: */
352: if ((bp->b_flags & B_BAD) != 0 && me->me_bb != NULL) {
353: (*me->me_bb)(drive, mp, bp);
354: goto out;
355: }
356:
357: /*
358: * If the transfer failed, give the driver a crack
359: * at fixing things up.
360: */
361: if (st != M_ST_SUCCESS) {
362: switch ((*me->me_ioerr)(drive, mp, bp)) {
363:
364: case MSCP_DONE: /* fixed */
365: break;
366:
367: case MSCP_RESTARTED: /* still working on it */
368: goto out;
369:
370: case MSCP_FAILED: /* no luck */
371: /* XXX must move to ra.c */
372: mscp_printevent(mp);
373: break;
374: }
375: }
376:
377: /*
378: * Set the residual count and mark the transfer as
379: * done. If the I/O wait queue is now empty, release
380: * the shared BDP, if any.
381: */
382: bp->b_resid = bp->b_bcount - mp->mscp_seq.seq_bytecount;
383: bus_dmamap_unload(mi->mi_dmat, mxi->mxi_dmam);
384:
385: (*mc->mc_ctlrdone)(mi->mi_dev.dv_parent);
386: (*me->me_iodone)(drive, bp);
387: out:
388: mxi->mxi_inuse = 0;
389: mi->mi_mxiuse |= (1 << mp->mscp_cmdref);
390: break;
391:
392: case M_OP_REPLACE | M_OP_END:
393: /*
394: * A replace operation finished. Just let the driver
395: * handle it (if it does replaces).
396: */
397: if (me->me_replace == NULL)
398: printf("%s: bogus REPLACE end\n", drive->dv_xname);
399: else
400: (*me->me_replace)(drive, mp);
401: break;
402:
403: default:
404: /*
405: * If it is not one of the above, we cannot handle it.
406: * (And we should not have received it, for that matter.)
407: */
408: unknown:
409: printf("%s: unknown opcode 0x%x status 0x%x ignored\n",
410: drive->dv_xname, mp->mscp_opcode, mp->mscp_status);
411: #ifdef DIAGNOSTIC
412: mscp_hexdump(mp);
413: #endif
414: break;
415: }
416:
417: /*
418: * If the drive needs to be put back in the controller queue,
419: * do that now. (`bp' below ought to be `dp', but they are all
420: * struct buf *.) Note that b_active was cleared in the driver;
421: * we presume that there is something to be done, hence reassert it.
422: */
423: #ifdef notyet /* XXX */
424: if (ui->ui_flags & UNIT_REQUEUE) {
425: ...
426: }
427: #endif
428: done:
429: /*
430: * Give back the response packet, and take a look at the next.
431: */
432: mp->mscp_msglen = MSCP_MSGLEN;
433: mi->mi_rsp.mri_desc[nextrsp] |= MSCP_OWN;
434: nextrsp = (nextrsp + 1) % mi->mi_rsp.mri_size;
435: goto loop;
436: }
437:
438: /*
439: * Requeue outstanding transfers, e.g., after bus reset.
440: * Also requeue any drives that have on line or unit status
441: * info pending.
442: */
443: void
444: mscp_requeue(mi)
445: struct mscp_softc *mi;
446: {
447: panic("mscp_requeue");
448: }
449:
CVSweb