1/* $NetBSD$ */ 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$"); 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 */ 103struct mscp * 104mscp_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 111again: 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 159int mscp_aeb_xor = 0x8000bb80; 160#endif 161 162/* 163 * Handle a response ring transition. 164 */ 165void 166mscp_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; 180loop: 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 workqueue_enqueue(mi->mi_wq, 318 (struct work *)mw, NULL); 319 } 320 } else 321 /* Hack to avoid complaints */ 322 if (!(((mp->mscp_event & M_ST_MASK) == M_ST_AVAILABLE) 323 && cold)) 324 (*me->me_gotstatus)(drive, mp); 325 break; 326 327 case M_OP_AVAILATTN: 328 /* 329 * The drive went offline and we did not notice. 330 * Mark it off line now, to force an on line request 331 * next, so we can make sure it is still the same 332 * drive. 333 * 334 * IF THE UDA DRIVER HAS A COMMAND AWAITING UNIBUS 335 * RESOURCES, THAT COMMAND MAY GO OUT BEFORE THE ON 336 * LINE. IS IT WORTH FIXING?? 337 */ 338#ifdef notyet 339 (*md->md_offline)(ui, mp); 340#endif 341 break; 342 343 case M_OP_POS | M_OP_END: 344 case M_OP_WRITM | M_OP_END: 345 case M_OP_AVAILABLE | M_OP_END: 346 /* 347 * A non-data transfer operation completed. 348 */ 349 (*me->me_cmddone)(drive, mp); 350 break; 351 352 case M_OP_READ | M_OP_END: 353 case M_OP_WRITE | M_OP_END: 354 /* 355 * A transfer finished. Get the buffer, and release its 356 * map registers via ubadone(). If the command finished 357 * with an off line or available status, the drive went 358 * off line (the idiot controller does not tell us until 359 * it comes back *on* line, or until we try to use it). 360 */ 361rwend: 362#ifdef DIAGNOSTIC 363 if (mp->mscp_cmdref >= NCMD) { 364 /* 365 * No buffer means there is a bug somewhere! 366 */ 367 printf("%s: io done, but bad xfer number?\n", 368 device_xname(drive)); 369 mscp_hexdump(mp); 370 break; 371 } 372#endif 373 374 if (mp->mscp_cmdref == -1) { 375 (*me->me_cmddone)(drive, mp); 376 break; 377 } 378 mxi = &mi->mi_xi[mp->mscp_cmdref]; 379 if (mxi->mxi_inuse == 0) 380 panic("mxi not inuse"); 381 bp = mxi->mxi_bp; 382 /* 383 * Mark any error-due-to-bad-LBN (via `goto rwend'). 384 * WHAT STATUS WILL THESE HAVE? IT SURE WOULD BE NICE 385 * IF DEC SOLD DOCUMENTATION FOR THEIR OWN CONTROLLERS. 386 */ 387 bp->b_error = error; 388 if (st == M_ST_OFFLINE || st == M_ST_AVAILABLE) { 389#ifdef notyet 390 (*md->md_offline)(ui, mp); 391#endif 392 } 393 394 /* 395 * If the transfer failed, give the driver a crack 396 * at fixing things up. 397 */ 398 if (st != M_ST_SUCCESS) { 399 switch ((*me->me_ioerr)(drive, mp, bp)) { 400 401 case MSCP_DONE: /* fixed */ 402 break; 403 404 case MSCP_RESTARTED: /* still working on it */ 405 goto out; 406 407 case MSCP_FAILED: /* no luck */ 408 /* XXX must move to ra.c */ 409 mscp_printevent(mp); 410 break; 411 } 412 } 413 414 /* 415 * Set the residual count and mark the transfer as 416 * done. If the I/O wait queue is now empty, release 417 * the shared BDP, if any. 418 */ 419 bp->b_resid = bp->b_bcount - mp->mscp_seq.seq_bytecount; 420 bus_dmamap_unload(mi->mi_dmat, mxi->mxi_dmam); 421 422 (*mc->mc_ctlrdone)(device_parent(&mi->mi_dev)); 423 (*me->me_iodone)(drive, bp); 424out: 425 mxi->mxi_inuse = 0; 426 mi->mi_mxiuse |= (1 << mp->mscp_cmdref); 427 break; 428 429 case M_OP_REPLACE | M_OP_END: 430 /* 431 * A replace operation finished. Just let the driver 432 * handle it (if it does replaces). 433 */ 434 if (me->me_replace == NULL) 435 printf("%s: bogus REPLACE end\n", device_xname(drive)); 436 else 437 (*me->me_replace)(drive, mp); 438 break; 439 440 default: 441 /* 442 * If it is not one of the above, we cannot handle it. 443 * (And we should not have received it, for that matter.) 444 */ 445unknown: 446 printf("%s: unknown opcode 0x%x status 0x%x ignored\n", 447 device_xname(drive), mp->mscp_opcode, mp->mscp_status); 448#ifdef DIAGNOSTIC 449 mscp_hexdump(mp); 450#endif 451 break; 452 } 453 454 /* 455 * If the drive needs to be put back in the controller queue, 456 * do that now. (`bp' below ought to be `dp', but they are all 457 * struct buf *.) Note that b_active was cleared in the driver; 458 * we presume that there is something to be done, hence reassert it. 459 */ 460#ifdef notyet /* XXX */ 461 if (ui->ui_flags & UNIT_REQUEUE) { 462 ... 463 } 464#endif 465done: 466 /* 467 * Give back the response packet, and take a look at the next. 468 */ 469 mp->mscp_msglen = MSCP_MSGLEN; 470 mi->mi_rsp.mri_desc[nextrsp] |= MSCP_OWN; 471 nextrsp = (nextrsp + 1) % mi->mi_rsp.mri_size; 472 goto loop; 473} 474 475/* 476 * Requeue outstanding transfers, e.g., after bus reset. 477 * Also requeue any drives that have on line or unit status 478 * info pending. 479 */ 480void 481mscp_requeue(struct mscp_softc *mi) 482{ 483 panic("mscp_requeue"); 484} 485 486void 487mscp_worker(struct work *wk, void *dummy) 488{ 489 struct mscp_softc *mi; 490 struct mscp_work *mw; 491 struct drive_attach_args da; 492 493 mw = (struct mscp_work *)wk; 494 mi = mw->mw_mi; 495 496 da.da_mp = &mw->mw_mp; 497 da.da_typ = mi->mi_type; 498 499 config_found(&mi->mi_dev, (void *)&da, mscp_print); 500 501 mutex_spin_enter(&mi->mi_mtx); 502 SLIST_INSERT_HEAD(&mw->mw_mi->mi_freelist, mw, mw_list); 503 mutex_spin_exit(&mi->mi_mtx); 504} 505