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