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