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