1 /* $NetBSD: mscp_tape.c,v 1.15 2000/03/30 12:45:34 augustss Exp $ */ 2 /* 3 * Copyright (c) 1996 Ludd, University of Lule}, Sweden. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed at Ludd, University of 17 * Lule}, Sweden and its contributors. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 34 /* 35 * MSCP tape device driver 36 */ 37 38 /* 39 * TODO 40 * Write status handling code. 41 */ 42 43 #include <sys/param.h> 44 #include <sys/device.h> 45 #include <sys/kernel.h> 46 #include <sys/buf.h> 47 #include <sys/ioccom.h> 48 #include <sys/mtio.h> 49 #include <sys/fcntl.h> 50 #include <sys/malloc.h> 51 #include <sys/systm.h> 52 #include <sys/proc.h> 53 54 #include <machine/bus.h> 55 #include <machine/cpu.h> 56 57 #include <dev/mscp/mscp.h> 58 #include <dev/mscp/mscpreg.h> 59 #include <dev/mscp/mscpvar.h> 60 61 #include "locators.h" 62 63 /* 64 * Drive status, per drive 65 */ 66 struct mt_softc { 67 struct device mt_dev; /* Autoconf struct */ 68 int mt_state; /* open/closed state */ 69 int mt_hwunit; /* Hardware unit number */ 70 int mt_inuse; /* Locks the tape drive for others */ 71 int mt_waswrite; /* Last operation was a write op */ 72 int mt_serex; /* Got serious exception */ 73 int mt_ioctlerr; /* Error after last ioctl */ 74 }; 75 76 #define MT_OFFLINE 0 77 #define MT_ONLINE 1 78 79 int mtmatch __P((struct device *, struct cfdata *, void *)); 80 void mtattach __P((struct device *, struct device *, void *)); 81 void mtdgram __P((struct device *, struct mscp *, struct mscp_softc *)); 82 void mtiodone __P((struct device *, struct buf *)); 83 int mtonline __P((struct device *, struct mscp *)); 84 int mtgotstatus __P((struct device *, struct mscp *)); 85 int mtioerror __P((struct device *, struct mscp *, struct buf *)); 86 void mtfillin __P((struct buf *, struct mscp *)); 87 int mtopen __P((dev_t, int, int, struct proc *)); 88 int mtclose __P((dev_t, int, int, struct proc *)); 89 void mtstrategy __P((struct buf *)); 90 int mtread __P((dev_t, struct uio *)); 91 int mtwrite __P((dev_t, struct uio *)); 92 int mtioctl __P((dev_t, int, caddr_t, int, struct proc *)); 93 int mtdump __P((dev_t, daddr_t, caddr_t, size_t)); 94 int mtcmd __P((struct mt_softc *, int, int, int)); 95 void mtcmddone __P((struct device *, struct mscp *)); 96 int mt_putonline __P((struct mt_softc *)); 97 98 struct mscp_device mt_device = { 99 mtdgram, 100 mtiodone, 101 mtonline, 102 mtgotstatus, 103 0, 104 mtioerror, 105 0, 106 mtfillin, 107 mtcmddone, 108 }; 109 110 /* This is not good, should allow more than 4 tapes/device type */ 111 #define mtunit(dev) (minor(dev) & T_UNIT) 112 #define mtnorewind(dev) (dev & T_NOREWIND) 113 #define mthdensity(dev) (dev & T_1600BPI) 114 115 struct cfattach mt_ca = { 116 sizeof(struct mt_softc), mtmatch, mtattach 117 }; 118 119 extern struct cfdriver mt_cd; 120 121 /* 122 * More driver definitions, for generic MSCP code. 123 */ 124 125 int 126 mtmatch(parent, cf, aux) 127 struct device *parent; 128 struct cfdata *cf; 129 void *aux; 130 { 131 struct drive_attach_args *da = aux; 132 struct mscp *mp = da->da_mp; 133 134 if ((da->da_typ & MSCPBUS_TAPE) == 0) 135 return 0; 136 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT && 137 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit) 138 return 0; 139 return 1; 140 } 141 142 /* 143 * The attach routine only checks and prints drive type. 144 */ 145 void 146 mtattach(parent, self, aux) 147 struct device *parent, *self; 148 void *aux; 149 { 150 struct mt_softc *mt = (void *)self; 151 struct drive_attach_args *da = aux; 152 struct mscp *mp = da->da_mp; 153 struct mscp_softc *mi = (void *)parent; 154 155 mt->mt_hwunit = mp->mscp_unit; 156 mi->mi_dp[mp->mscp_unit] = self; 157 158 disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid); 159 } 160 161 /* 162 * (Try to) put the drive online. This is done the first time the 163 * drive is opened, or if it has fallen offline. 164 */ 165 int 166 mt_putonline(mt) 167 struct mt_softc *mt; 168 { 169 struct mscp *mp; 170 struct mscp_softc *mi = (struct mscp_softc *)mt->mt_dev.dv_parent; 171 volatile int i; 172 173 (volatile int)mt->mt_state = MT_OFFLINE; 174 mp = mscp_getcp(mi, MSCP_WAIT); 175 mp->mscp_opcode = M_OP_ONLINE; 176 mp->mscp_unit = mt->mt_hwunit; 177 mp->mscp_cmdref = (long)&mt->mt_state; 178 *mp->mscp_addr |= MSCP_OWN | MSCP_INT; 179 180 /* Poll away */ 181 i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0); 182 if (tsleep(&mt->mt_state, PRIBIO, "mtonline", 240 * hz)) 183 return MSCP_FAILED; 184 185 if ((volatile int)mt->mt_state != MT_ONLINE) 186 return MSCP_FAILED; 187 188 return MSCP_DONE; 189 } 190 /* 191 * Open a drive. 192 */ 193 /*ARGSUSED*/ 194 int 195 mtopen(dev, flag, fmt, p) 196 dev_t dev; 197 int flag, fmt; 198 struct proc *p; 199 { 200 struct mt_softc *mt; 201 int unit; 202 203 /* 204 * Make sure this is a reasonable open request. 205 */ 206 unit = mtunit(dev); 207 if (unit >= mt_cd.cd_ndevs) 208 return ENXIO; 209 mt = mt_cd.cd_devs[unit]; 210 if (mt == 0) 211 return ENXIO; 212 213 if (mt->mt_inuse) 214 return EBUSY; 215 mt->mt_inuse = 1; 216 217 if (mt_putonline(mt) == MSCP_FAILED) { 218 mt->mt_inuse = 0; 219 return EIO; 220 } 221 222 return 0; 223 } 224 225 /* ARGSUSED */ 226 int 227 mtclose(dev, flags, fmt, p) 228 dev_t dev; 229 int flags, fmt; 230 struct proc *p; 231 { 232 int unit = mtunit(dev); 233 struct mt_softc *mt = mt_cd.cd_devs[unit]; 234 235 /* 236 * If we just have finished a writing, write EOT marks. 237 */ 238 if ((flags & FWRITE) && mt->mt_waswrite) { 239 mtcmd(mt, MTWEOF, 0, 0); 240 mtcmd(mt, MTWEOF, 0, 0); 241 mtcmd(mt, MTBSR, 1, 0); 242 } 243 if (mtnorewind(dev) == 0) 244 mtcmd(mt, MTREW, 0, 1); 245 if (mt->mt_serex) 246 mtcmd(mt, -1, 0, 0); 247 248 mt->mt_inuse = 0; /* Release the tape */ 249 return 0; 250 } 251 252 void 253 mtstrategy(bp) 254 struct buf *bp; 255 { 256 int unit; 257 struct mt_softc *mt; 258 259 /* 260 * Make sure this is a reasonable drive to use. 261 */ 262 unit = mtunit(bp->b_dev); 263 if (unit > mt_cd.cd_ndevs || (mt = mt_cd.cd_devs[unit]) == NULL) { 264 bp->b_error = ENXIO; 265 goto bad; 266 } 267 268 mt->mt_waswrite = bp->b_flags & B_READ ? 0 : 1; 269 mscp_strategy(bp, mt->mt_dev.dv_parent); 270 return; 271 272 bad: 273 bp->b_flags |= B_ERROR; 274 biodone(bp); 275 } 276 277 int 278 mtread(dev, uio) 279 dev_t dev; 280 struct uio *uio; 281 { 282 283 return (physio(mtstrategy, NULL, dev, B_READ, minphys, uio)); 284 } 285 286 int 287 mtwrite(dev, uio) 288 dev_t dev; 289 struct uio *uio; 290 { 291 292 return (physio(mtstrategy, NULL, dev, B_WRITE, minphys, uio)); 293 } 294 295 void 296 mtiodone(usc, bp) 297 struct device *usc; 298 struct buf *bp; 299 { 300 301 biodone(bp); 302 } 303 304 /* 305 * Fill in drive addresses in a mscp packet waiting for transfer. 306 */ 307 void 308 mtfillin(bp, mp) 309 struct buf *bp; 310 struct mscp *mp; 311 { 312 int unit = mtunit(bp->b_dev); 313 struct mt_softc *mt = mt_cd.cd_devs[unit]; 314 315 mp->mscp_unit = mt->mt_hwunit; 316 if (mt->mt_serex == 2) { 317 mp->mscp_modifier = M_MD_CLSEX; 318 mt->mt_serex = 0; 319 } else 320 mp->mscp_modifier = 0; 321 322 mp->mscp_seq.seq_bytecount = bp->b_bcount; 323 } 324 325 /* 326 * Handle an error datagram. 327 */ 328 void 329 mtdgram(usc, mp, mi) 330 struct device *usc; 331 struct mscp *mp; 332 struct mscp_softc *mi; 333 { 334 if (mscp_decodeerror(usc == NULL?"unconf mt" : usc->dv_xname, mp, mi)) 335 return; 336 } 337 338 /* 339 * A drive came on line, make sure it really _is_ on line before 340 * trying to use it. 341 */ 342 int 343 mtonline(usc, mp) 344 struct device *usc; 345 struct mscp *mp; 346 { 347 struct mt_softc *mt = (void *)usc; 348 349 wakeup((caddr_t)&mt->mt_state); 350 if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS) 351 mt->mt_state = MT_ONLINE; 352 353 return (MSCP_DONE); 354 } 355 356 /* 357 * We got some (configured) unit's status. Return DONE. 358 */ 359 int 360 mtgotstatus(usc, mp) 361 struct device *usc; 362 struct mscp *mp; 363 { 364 return (MSCP_DONE); 365 } 366 367 static char *mt_ioerrs[] = { 368 "invalid command", /* 1 M_ST_INVALCMD */ 369 "command aborted", /* 2 M_ST_ABORTED */ 370 "unit offline", /* 3 M_ST_OFFLINE */ 371 "unknown", /* 4 M_ST_AVAILABLE */ 372 "unknown", /* 5 M_ST_MFMTERR */ 373 "unit write protected", /* 6 M_ST_WRPROT */ 374 "compare error", /* 7 M_ST_COMPERR */ 375 "data error", /* 8 M_ST_DATAERR */ 376 "host buffer access error", /* 9 M_ST_HOSTBUFERR */ 377 "controller error", /* 10 M_ST_CTLRERR */ 378 "drive error", /* 11 M_ST_DRIVEERR */ 379 "formatter error", /* 12 M_ST_FORMATTERR */ 380 "BOT encountered", /* 13 M_ST_BOT */ 381 "tape mark encountered",/* 14 M_ST_TAPEMARK */ 382 "unknown", /* 15 */ 383 "record data truncated",/* 16 M_ST_RDTRUNC */ 384 }; 385 386 /* 387 * An I/O error, may be because of a tapemark encountered. 388 * Check that before failing. 389 */ 390 /*ARGSUSED*/ 391 int 392 mtioerror(usc, mp, bp) 393 struct device *usc; 394 struct mscp *mp; 395 struct buf *bp; 396 { 397 struct mt_softc *mt = (void *)usc; 398 int st = mp->mscp_status & M_ST_MASK; 399 400 if (mp->mscp_flags & M_EF_SEREX) 401 mt->mt_serex = 1; 402 if (st == M_ST_TAPEMARK) 403 mt->mt_serex = 2; 404 else { 405 if (st && st < 17) 406 printf("%s: error %d (%s)\n", mt->mt_dev.dv_xname, st, 407 mt_ioerrs[st-1]); 408 else 409 printf("%s: error %d\n", mt->mt_dev.dv_xname, st); 410 bp->b_flags |= B_ERROR; 411 bp->b_error = EROFS; 412 } 413 414 return (MSCP_DONE); 415 } 416 417 /* 418 * I/O controls. 419 */ 420 int 421 mtioctl(dev, cmd, data, flag, p) 422 dev_t dev; 423 int cmd; 424 caddr_t data; 425 int flag; 426 struct proc *p; 427 { 428 int unit = mtunit(dev); 429 struct mt_softc *mt = mt_cd.cd_devs[unit]; 430 struct mtop *mtop; 431 struct mtget *mtget; 432 int error = 0, count; 433 434 count = mtop->mt_count; 435 436 switch (cmd) { 437 438 case MTIOCTOP: 439 mtop = (void *)data; 440 if (mtop->mt_op == MTWEOF) { 441 while (mtop->mt_count-- > 0) 442 if ((error = mtcmd(mt, mtop->mt_op, 0, 0))) 443 break; 444 } else 445 error = mtcmd(mt, mtop->mt_op, mtop->mt_count, 0); 446 447 case MTIOCGET: 448 mtget = (void *)data; 449 mtget->mt_type = MT_ISTMSCP; 450 /* XXX we need to fill in more fields here */ 451 break; 452 453 default: 454 error = ENXIO; 455 break; 456 } 457 return (error); 458 } 459 460 /* 461 * No crash dump support... 462 */ 463 int 464 mtdump(dev, blkno, va, size) 465 dev_t dev; 466 daddr_t blkno; 467 caddr_t va; 468 size_t size; 469 { 470 return -1; 471 } 472 473 /* 474 * Send a command to the tape drive. Wait until the command is 475 * finished before returning. 476 * This routine must only be called when there are no data transfer 477 * active on this device. Can we be sure of this? Or does the ctlr 478 * queue up all command packets and take them in sequential order? 479 * It sure would be nice if my manual stated this... /ragge 480 */ 481 int 482 mtcmd(mt, cmd, count, complete) 483 struct mt_softc *mt; 484 int cmd, count, complete; 485 { 486 struct mscp *mp; 487 struct mscp_softc *mi = (void *)mt->mt_dev.dv_parent; 488 volatile int i; 489 490 mp = mscp_getcp(mi, MSCP_WAIT); 491 492 mt->mt_ioctlerr = 0; 493 mp->mscp_unit = mt->mt_hwunit; 494 mp->mscp_cmdref = -1; 495 *mp->mscp_addr |= MSCP_OWN | MSCP_INT; 496 497 switch (cmd) { 498 case MTWEOF: 499 mp->mscp_opcode = M_OP_WRITM; 500 break; 501 502 case MTBSF: 503 mp->mscp_modifier = M_MD_REVERSE; 504 case MTFSF: 505 mp->mscp_opcode = M_OP_POS; 506 mp->mscp_seq.seq_buffer = count; 507 break; 508 509 case MTBSR: 510 mp->mscp_modifier = M_MD_REVERSE; 511 case MTFSR: 512 mp->mscp_opcode = M_OP_POS; 513 mp->mscp_modifier |= M_MD_OBJCOUNT; 514 mp->mscp_seq.seq_bytecount = count; 515 break; 516 517 case MTREW: 518 mp->mscp_opcode = M_OP_POS; 519 mp->mscp_modifier = M_MD_REWIND | M_MD_CLSEX; 520 if (complete) 521 mp->mscp_modifier |= M_MD_IMMEDIATE; 522 mt->mt_serex = 0; 523 break; 524 525 case MTOFFL: 526 mp->mscp_opcode = M_OP_AVAILABLE; 527 mp->mscp_modifier = M_MD_UNLOAD | M_MD_CLSEX; 528 mt->mt_serex = 0; 529 break; 530 531 case MTNOP: 532 mp->mscp_opcode = M_OP_GETUNITST; 533 break; 534 535 case -1: /* Clear serious exception only */ 536 mp->mscp_opcode = M_OP_POS; 537 mp->mscp_modifier = M_MD_CLSEX; 538 mt->mt_serex = 0; 539 break; 540 541 default: 542 printf("Bad ioctl %x\n", cmd); 543 mp->mscp_opcode = M_OP_POS; 544 break; 545 } 546 547 i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0); 548 tsleep(&mt->mt_inuse, PRIBIO, "mtioctl", 0); 549 return mt->mt_ioctlerr; 550 } 551 552 /* 553 * Called from bus routines whenever a non-data transfer is finished. 554 */ 555 void 556 mtcmddone(usc, mp) 557 struct device *usc; 558 struct mscp *mp; 559 { 560 struct mt_softc *mt = (void *)usc; 561 562 if (mp->mscp_status) { 563 mt->mt_ioctlerr = EIO; 564 printf("%s: bad status %x\n", mt->mt_dev.dv_xname, 565 mp->mscp_status); 566 } 567 wakeup(&mt->mt_inuse); 568 } 569