1 /*        $NetBSD: mscp.c,v 1.39 2024/01/11 06:19:49 mrg 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.39 2024/01/11 06:19:49 mrg 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 *
mscp_getcp(struct mscp_softc * mi,int canwait)104 mscp_getcp(struct mscp_softc *mi, int canwait)
105 {
106 #define mri         (&mi->mi_cmd)
107           struct mscp *mp;
108           int i;
109           int s = spluba();
110 
111 again:
112           /*
113            * Ensure that we have some command credits, and
114            * that the next command packet is free.
115            */
116           if (mi->mi_credits <= MSCP_MINCREDITS) {
117                     if (!canwait) {
118                               splx(s);
119                               return (NULL);
120                     }
121                     mi->mi_wantcredits = 1;
122                     (void) tsleep(&mi->mi_wantcredits, PCMD, "mscpwcrd", 0);
123                     goto again;
124           }
125           i = mri->mri_next;
126           if (mri->mri_desc[i] & MSCP_OWN) {
127                     if (!canwait) {
128                               splx(s);
129                               return (NULL);
130                     }
131                     mi->mi_wantcmd = 1;
132                     (void) tsleep(&mi->mi_wantcmd, PCMD, "mscpwcmd", 0);
133                     goto again;
134           }
135           mi->mi_credits--;
136           mri->mri_desc[i] &= ~MSCP_INT;
137           mri->mri_next = (mri->mri_next + 1) % mri->mri_size;
138           splx(s);
139           mp = &mri->mri_ring[i];
140 
141           /*
142            * Initialise some often-zero fields.
143            * ARE THE LAST TWO NECESSARY IN GENERAL?  IT SURE WOULD BE
144            * NICE IF DEC SOLD DOCUMENTATION FOR THEIR OWN CONTROLLERS.
145            */
146           mp->mscp_msglen = MSCP_MSGLEN;
147           mp->mscp_flags = 0;
148           mp->mscp_modifier = 0;
149           mp->mscp_seq.seq_bytecount = 0;
150           mp->mscp_seq.seq_buffer = 0;
151           mp->mscp_seq.seq_mapbase = 0;
152 /*???*/ mp->mscp_sccc.sccc_errlgfl = 0;
153 /*???*/ mp->mscp_sccc.sccc_copyspd = 0;
154           return (mp);
155 #undef    mri
156 }
157 
158 #ifdef AVOID_EMULEX_BUG
159 int       mscp_aeb_xor = 0x8000bb80;
160 #endif
161 
162 /*
163  * Handle a response ring transition.
164  */
165 void
mscp_dorsp(struct mscp_softc * mi)166 mscp_dorsp(struct mscp_softc *mi)
167 {
168           device_t drive;
169           struct mscp_device *me = mi->mi_me;
170           struct mscp_ctlr *mc = mi->mi_mc;
171           struct buf *bp;
172           struct mscp *mp;
173           struct mscp_xi *mxi;
174           int nextrsp;
175           int st, error;
176           extern struct mscp mscp_cold_reply;
177           extern int mscp_cold_unit;
178 
179           nextrsp = mi->mi_rsp.mri_next;
180 loop:
181           if (mi->mi_rsp.mri_desc[nextrsp] & MSCP_OWN) {
182                     /*
183                      * No more responses.  Remember the next expected
184                      * response index.  Check to see if we have some
185                      * credits back, and wake up sleepers if so.
186                      */
187                     mi->mi_rsp.mri_next = nextrsp;
188                     if (mi->mi_wantcredits && mi->mi_credits > MSCP_MINCREDITS) {
189                               mi->mi_wantcredits = 0;
190                               wakeup((void *) &mi->mi_wantcredits);
191                     }
192                     return;
193           }
194 
195           mp = &mi->mi_rsp.mri_ring[nextrsp];
196           mi->mi_credits += MSCP_CREDITS(mp->mscp_msgtc);
197           /*
198            * Controllers are allowed to interrupt as any drive, so we
199            * must check the command before checking for a drive.
200            */
201           if (mp->mscp_opcode == (M_OP_SETCTLRC | M_OP_END)) {
202                     if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS) {
203                               mi->mi_flags |= MSC_READY;
204                     } else {
205                               printf("%s: SETCTLRC failed: %d ",
206                                   device_xname(mi->mi_dev), mp->mscp_status);
207                               mscp_printevent(mp);
208                     }
209                     goto done;
210           }
211 
212           /*
213            * Found a response.  Update credit information.  If there is
214            * nothing else to do, jump to `done' to get the next response.
215            */
216           if (mp->mscp_unit >= mi->mi_driveno) { /* Must expand drive table */
217                     int tmpno = (mp->mscp_unit + 32) & ~31;
218                     device_t *tmp = (device_t *)
219                         malloc(tmpno * sizeof(tmp[0]), M_DEVBUF, M_NOWAIT|M_ZERO);
220                     /* XXX tmp should be checked for NULL */
221                     if (mi->mi_driveno) {
222                               memcpy(tmp, mi->mi_dp, mi->mi_driveno * sizeof(tmp[0]));
223                               free(mi->mi_dp, M_DEVBUF);
224                     }
225                     mi->mi_driveno = tmpno;
226                     mi->mi_dp = tmp;
227           }
228 
229           drive = mi->mi_dp[mp->mscp_unit];
230 
231           switch (MSCP_MSGTYPE(mp->mscp_msgtc)) {
232 
233           case MSCPT_SEQ:
234                     break;
235 
236           case MSCPT_DATAGRAM:
237                     (*me->me_dgram)(drive, mp, mi);
238                     goto done;
239 
240           case MSCPT_CREDITS:
241                     goto done;
242 
243           case MSCPT_MAINTENANCE:
244           default:
245                     printf("%s: unit %d: unknown message type 0x%x ignored\n",
246                               device_xname(mi->mi_dev), mp->mscp_unit,
247                               MSCP_MSGTYPE(mp->mscp_msgtc));
248                     goto done;
249           }
250 
251           /*
252            * Handle individual responses.
253            */
254           st = mp->mscp_status & M_ST_MASK;
255           error = 0;
256           switch (mp->mscp_opcode) {
257 
258           case M_OP_END:
259                     /*
260                      * The controller presents a bogus END packet when
261                      * a read/write command is given with an illegal
262                      * block number.  This is contrary to the MSCP
263                      * specification (ENDs are to be given only for
264                      * invalid commands), but that is the way of it.
265                      */
266                     if (st == M_ST_INVALCMD && mp->mscp_cmdref != 0) {
267                               printf("%s: bad lbn (%d)?\n", device_xname(drive),
268                                         (int)mp->mscp_seq.seq_lbn);
269                               error = EIO;
270                               goto rwend;
271                     }
272                     goto unknown;
273 
274           case M_OP_ONLINE | M_OP_END:
275                     /*
276                      * Finished an ON LINE request.          Call the driver to
277                      * find out whether it succeeded.  If so, mark it on
278                      * line.
279                      */
280                     (*me->me_online)(drive, mp);
281                     break;
282 
283           case M_OP_GETUNITST | M_OP_END:
284                     /*
285                      * Got unit status.  If we are autoconfiguring, save
286                      * the mscp struct so that mscp_attach know what to do.
287                      * If the drive isn't configured, call config_found()
288                      * to set it up, otherwise it's just a "normal" unit
289                      * status.
290                      */
291                     if (cold) {
292                               memcpy(&mscp_cold_reply, mp, sizeof(struct mscp));
293                               /* Detect that we've reached the end of all units */
294                               if (mp->mscp_unit < mscp_cold_unit)
295                                         break;
296                     }
297 
298                     if (mp->mscp_status == (M_ST_OFFLINE|M_OFFLINE_UNKNOWN))
299                               break;
300 
301                     if (drive == 0) {
302                               struct mscp_work *mw;
303 
304                               mutex_spin_enter(&mi->mi_mtx);
305 
306                               mw = SLIST_FIRST(&mi->mi_freelist);
307                               if (mw == NULL) {
308                                         aprint_error_dev(mi->mi_dev,
309                                             "couldn't attach drive (no free items)\n");
310                                         mutex_spin_exit(&mi->mi_mtx);
311                               } else {
312                                         SLIST_REMOVE_HEAD(&mi->mi_freelist, mw_list);
313                                         mutex_spin_exit(&mi->mi_mtx);
314 
315                                         mw->mw_mi = mi;
316                                         mw->mw_mp = *mp;
317                                         mw->mw_online = false;
318                                         workqueue_enqueue(mi->mi_wq,
319                                             (struct work *)mw, NULL);
320                               }
321                     } else
322                               /* Hack to avoid complaints */
323                               if (!(((mp->mscp_event & M_ST_MASK) == M_ST_AVAILABLE)
324                                   && cold))
325                                         (*me->me_gotstatus)(drive, mp);
326                     break;
327 
328           case M_OP_AVAILATTN:
329                     /*
330                      * The drive went offline and we did not notice.
331                      * Mark it off line now, to force an on line request
332                      * next, so we can make sure it is still the same
333                      * drive.
334                      *
335                      * IF THE UDA DRIVER HAS A COMMAND AWAITING UNIBUS
336                      * RESOURCES, THAT COMMAND MAY GO OUT BEFORE THE ON
337                      * LINE.  IS IT WORTH FIXING??
338                      */
339 #ifdef notyet
340                     (*md->md_offline)(ui, mp);
341 #endif
342                     break;
343 
344           case M_OP_POS | M_OP_END:
345           case M_OP_WRITM | M_OP_END:
346           case M_OP_AVAILABLE | M_OP_END:
347                     /*
348                      * A non-data transfer operation completed.
349                      */
350                     (*me->me_cmddone)(drive, mp);
351                     break;
352 
353           case M_OP_READ | M_OP_END:
354           case M_OP_WRITE | M_OP_END:
355                     /*
356                      * A transfer finished.        Get the buffer, and release its
357                      * map registers via ubadone().          If the command finished
358                      * with an off line or available status, the drive went
359                      * off line (the idiot controller does not tell us until
360                      * it comes back *on* line, or until we try to use it).
361                      */
362 rwend:
363 #ifdef DIAGNOSTIC
364                     if (mp->mscp_cmdref >= NCMD) {
365                               /*
366                                * No buffer means there is a bug somewhere!
367                                */
368                               printf("%s: io done, but bad xfer number?\n",
369                                   device_xname(drive));
370                               mscp_hexdump(mp);
371                               break;
372                     }
373 #endif
374 
375                     if (mp->mscp_cmdref == -1) {
376                               (*me->me_cmddone)(drive, mp);
377                               break;
378                     }
379                     mxi = &mi->mi_xi[mp->mscp_cmdref];
380                     if (mxi->mxi_inuse == 0)
381                               panic("mxi not inuse");
382                     bp = mxi->mxi_bp;
383                     /*
384                      * Mark any error-due-to-bad-LBN (via `goto rwend').
385                      * WHAT STATUS WILL THESE HAVE?          IT SURE WOULD BE NICE
386                      * IF DEC SOLD DOCUMENTATION FOR THEIR OWN CONTROLLERS.
387                      */
388                     bp->b_error = error;
389                     if (st == M_ST_OFFLINE || st == M_ST_AVAILABLE) {
390 #ifdef notyet
391                               (*md->md_offline)(ui, mp);
392 #endif
393                     }
394 
395                     /*
396                      * If the transfer failed, give the driver a crack
397                      * at fixing things up.
398                      */
399                     if (st != M_ST_SUCCESS) {
400                               switch ((*me->me_ioerr)(drive, mp, bp)) {
401 
402                               case MSCP_DONE:               /* fixed */
403                                         break;
404 
405                               case MSCP_RESTARTED:          /* still working on it */
406                                         goto out;
407 
408                               case MSCP_FAILED:   /* no luck */
409                                         /* XXX must move to ra.c */
410                                         mscp_printevent(mp);
411                                         break;
412                               }
413                     }
414 
415                     /*
416                      * Set the residual count and mark the transfer as
417                      * done.  If the I/O wait queue is now empty, release
418                      * the shared BDP, if any.
419                      */
420                     bp->b_resid = bp->b_bcount - mp->mscp_seq.seq_bytecount;
421                     bus_dmamap_unload(mi->mi_dmat, mxi->mxi_dmam);
422 
423                     (*mc->mc_ctlrdone)(device_parent(mi->mi_dev));
424                     (*me->me_iodone)(drive, bp);
425 out:
426                     mxi->mxi_inuse = 0;
427                     mi->mi_mxiuse |= (1 << mp->mscp_cmdref);
428                     break;
429 
430           case M_OP_REPLACE | M_OP_END:
431                     /*
432                      * A replace operation finished.  Just let the driver
433                      * handle it (if it does replaces).
434                      */
435                     if (me->me_replace == NULL)
436                               printf("%s: bogus REPLACE end\n", device_xname(drive));
437                     else
438                               (*me->me_replace)(drive, mp);
439                     break;
440 
441           default:
442                     /*
443                      * If it is not one of the above, we cannot handle it.
444                      * (And we should not have received it, for that matter.)
445                      */
446 unknown:
447                     printf("%s: unknown opcode 0x%x status 0x%x ignored\n",
448                               device_xname(drive), mp->mscp_opcode, mp->mscp_status);
449 #ifdef DIAGNOSTIC
450                     mscp_hexdump(mp);
451 #endif
452                     break;
453           }
454 
455           /*
456            * If the drive needs to be put back in the controller queue,
457            * do that now.      (`bp' below ought to be `dp', but they are all
458            * struct buf *.)  Note that b_active was cleared in the driver;
459            * we presume that there is something to be done, hence reassert it.
460            */
461 #ifdef notyet /* XXX */
462           if (ui->ui_flags & UNIT_REQUEUE) {
463                     ...
464           }
465 #endif
466 done:
467           /*
468            * Give back the response packet, and take a look at the next.
469            */
470           mp->mscp_msglen = MSCP_MSGLEN;
471           mi->mi_rsp.mri_desc[nextrsp] |= MSCP_OWN;
472           nextrsp = (nextrsp + 1) % mi->mi_rsp.mri_size;
473           goto loop;
474 }
475 
476 /*
477  * Requeue outstanding transfers, e.g., after bus reset.
478  * Also requeue any drives that have on line or unit status
479  * info pending.
480  */
481 void
mscp_requeue(struct mscp_softc * mi)482 mscp_requeue(struct mscp_softc *mi)
483 {
484           panic("mscp_requeue");
485 }
486 
487 /*
488  * mscp_worker: Complete configuration and online events.
489  *
490  * If the new work mw_online is false, this is an autoconfiguration
491  * event, otherwise it is a online event that needs to be handled
492  * in a thread context.
493  */
494 void
mscp_worker(struct work * wk,void * arg)495 mscp_worker(struct work *wk, void *arg)
496 {
497           struct mscp_work *mw = (struct mscp_work *)wk;
498           struct mscp_softc *mi = mw->mw_mi;
499           struct drive_attach_args da;
500 
501           /* This is an online event. */
502           if (mw->mw_online) {
503                     struct mscp_device *me = mi->mi_me;
504 
505                     if (me->me_online_cb)
506                               return (*me->me_online_cb)(wk);
507                     /* Must be cb for this type. */
508                     panic("mscp_worker");
509           }
510 
511           da.da_mp = &mw->mw_mp;
512           da.da_typ = mi->mi_type;
513 
514           config_found(mi->mi_dev, (void *)&da, mscp_print, CFARGS_NONE);
515 
516           mutex_spin_enter(&mi->mi_mtx);
517           SLIST_INSERT_HEAD(&mw->mw_mi->mi_freelist, mw, mw_list);
518           mutex_spin_exit(&mi->mi_mtx);
519 }
520