FreeBSD/Linux Kernel Cross Reference
sys/dev/mscp/mscp.c
1 /* $NetBSD: mscp.c,v 1.29 2008/04/08 20:10:44 cegger 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.29 2008/04/08 20:10:44 cegger 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 <sys/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((void *) &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 device_xname(&mi->mi_dev), 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 device_xname(&mi->mi_dev), 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", device_xname(drive),
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 device_xname(drive));
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 bp->b_error = error;
373 if (st == M_ST_OFFLINE || st == M_ST_AVAILABLE) {
374 #ifdef notyet
375 (*md->md_offline)(ui, mp);
376 #endif
377 }
378
379 /*
380 * If the transfer failed, give the driver a crack
381 * at fixing things up.
382 */
383 if (st != M_ST_SUCCESS) {
384 switch ((*me->me_ioerr)(drive, mp, bp)) {
385
386 case MSCP_DONE: /* fixed */
387 break;
388
389 case MSCP_RESTARTED: /* still working on it */
390 goto out;
391
392 case MSCP_FAILED: /* no luck */
393 /* XXX must move to ra.c */
394 mscp_printevent(mp);
395 break;
396 }
397 }
398
399 /*
400 * Set the residual count and mark the transfer as
401 * done. If the I/O wait queue is now empty, release
402 * the shared BDP, if any.
403 */
404 bp->b_resid = bp->b_bcount - mp->mscp_seq.seq_bytecount;
405 bus_dmamap_unload(mi->mi_dmat, mxi->mxi_dmam);
406
407 (*mc->mc_ctlrdone)(device_parent(&mi->mi_dev));
408 (*me->me_iodone)(drive, bp);
409 out:
410 mxi->mxi_inuse = 0;
411 mi->mi_mxiuse |= (1 << mp->mscp_cmdref);
412 break;
413
414 case M_OP_REPLACE | M_OP_END:
415 /*
416 * A replace operation finished. Just let the driver
417 * handle it (if it does replaces).
418 */
419 if (me->me_replace == NULL)
420 printf("%s: bogus REPLACE end\n", device_xname(drive));
421 else
422 (*me->me_replace)(drive, mp);
423 break;
424
425 default:
426 /*
427 * If it is not one of the above, we cannot handle it.
428 * (And we should not have received it, for that matter.)
429 */
430 unknown:
431 printf("%s: unknown opcode 0x%x status 0x%x ignored\n",
432 device_xname(drive), mp->mscp_opcode, mp->mscp_status);
433 #ifdef DIAGNOSTIC
434 mscp_hexdump(mp);
435 #endif
436 break;
437 }
438
439 /*
440 * If the drive needs to be put back in the controller queue,
441 * do that now. (`bp' below ought to be `dp', but they are all
442 * struct buf *.) Note that b_active was cleared in the driver;
443 * we presume that there is something to be done, hence reassert it.
444 */
445 #ifdef notyet /* XXX */
446 if (ui->ui_flags & UNIT_REQUEUE) {
447 ...
448 }
449 #endif
450 done:
451 /*
452 * Give back the response packet, and take a look at the next.
453 */
454 mp->mscp_msglen = MSCP_MSGLEN;
455 mi->mi_rsp.mri_desc[nextrsp] |= MSCP_OWN;
456 nextrsp = (nextrsp + 1) % mi->mi_rsp.mri_size;
457 goto loop;
458 }
459
460 /*
461 * Requeue outstanding transfers, e.g., after bus reset.
462 * Also requeue any drives that have on line or unit status
463 * info pending.
464 */
465 void
466 mscp_requeue(mi)
467 struct mscp_softc *mi;
468 {
469 panic("mscp_requeue");
470 }
471
Cache object: 6e18e34a14a3ef6daad7bd5b1c76d794
|