1 1.36 andvar /* $NetBSD: ts.c,v 1.36 2022/04/17 21:24:53 andvar Exp $ */ 2 1.1 ragge 3 1.1 ragge /*- 4 1.1 ragge * Copyright (c) 1991 The Regents of the University of California. 5 1.1 ragge * All rights reserved. 6 1.1 ragge * 7 1.1 ragge * Redistribution and use in source and binary forms, with or without 8 1.1 ragge * modification, are permitted provided that the following conditions 9 1.1 ragge * are met: 10 1.1 ragge * 1. Redistributions of source code must retain the above copyright 11 1.1 ragge * notice, this list of conditions and the following disclaimer. 12 1.1 ragge * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 ragge * notice, this list of conditions and the following disclaimer in the 14 1.1 ragge * documentation and/or other materials provided with the distribution. 15 1.11 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 ragge * may be used to endorse or promote products derived from this software 17 1.1 ragge * without specific prior written permission. 18 1.1 ragge * 19 1.1 ragge * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 ragge * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 ragge * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 ragge * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 ragge * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 ragge * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 ragge * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 ragge * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 ragge * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 ragge * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 ragge * SUCH DAMAGE. 30 1.1 ragge * 31 1.1 ragge * @(#)tmscp.c 7.16 (Berkeley) 5/9/91 32 1.1 ragge */ 33 1.1 ragge 34 1.1 ragge /* 35 1.1 ragge * sccsid = "@(#)tmscp.c 1.24 (ULTRIX) 1/21/86"; 36 1.1 ragge */ 37 1.1 ragge 38 1.1 ragge /************************************************************************ 39 1.1 ragge * * 40 1.1 ragge * Licensed from Digital Equipment Corporation * 41 1.1 ragge * Copyright (c) * 42 1.1 ragge * Digital Equipment Corporation * 43 1.1 ragge * Maynard, Massachusetts * 44 1.1 ragge * 1985, 1986 * 45 1.1 ragge * All rights reserved. * 46 1.1 ragge * * 47 1.1 ragge * The Information in this software is subject to change * 48 1.1 ragge * without notice and should not be construed as a commitment * 49 1.1 ragge * by Digital Equipment Corporation. Digital makes no * 50 1.1 ragge * representations about the suitability of this software for * 51 1.1 ragge * any purpose. It is supplied "As Is" without expressed or * 52 1.1 ragge * implied warranty. * 53 1.1 ragge * * 54 1.1 ragge * If the Regents of the University of California or its * 55 1.1 ragge * licensees modify the software in a manner creating * 56 1.1 ragge * derivative copyright rights, appropriate copyright * 57 1.1 ragge * legends may be placed on the derivative work in addition * 58 1.1 ragge * to that set forth above. * 59 1.1 ragge * * 60 1.1 ragge ************************************************************************/ 61 1.1 ragge 62 1.1 ragge /* 63 1.1 ragge * TSV05/TS05 device driver, written by Bertram Barth. 64 1.1 ragge * 65 1.1 ragge * should be TS11 compatible (untested) 66 1.1 ragge */ 67 1.3 lukem 68 1.3 lukem #include <sys/cdefs.h> 69 1.36 andvar __KERNEL_RCSID(0, "$NetBSD: ts.c,v 1.36 2022/04/17 21:24:53 andvar Exp $"); 70 1.1 ragge 71 1.2 ragge #undef TSDEBUG 72 1.1 ragge 73 1.1 ragge /* 74 1.2 ragge * TODO: 75 1.1 ragge * 76 1.2 ragge * Keep track of tape position so that lseek et al works. 77 1.2 ragge * Use tprintf to inform the user, not the system console. 78 1.1 ragge */ 79 1.1 ragge 80 1.1 ragge 81 1.1 ragge #include <sys/param.h> 82 1.1 ragge #include <sys/systm.h> 83 1.1 ragge #include <sys/kernel.h> 84 1.1 ragge #include <sys/buf.h> 85 1.12 yamt #include <sys/bufq.h> 86 1.1 ragge #include <sys/conf.h> 87 1.28 matt #include <sys/device.h> 88 1.1 ragge #include <sys/errno.h> 89 1.1 ragge #include <sys/file.h> 90 1.1 ragge #include <sys/syslog.h> 91 1.1 ragge #include <sys/ioctl.h> 92 1.1 ragge #include <sys/mtio.h> 93 1.1 ragge #include <sys/uio.h> 94 1.1 ragge #include <sys/proc.h> 95 1.1 ragge 96 1.21 ad #include <sys/bus.h> 97 1.1 ragge 98 1.1 ragge #include <dev/qbus/ubareg.h> 99 1.1 ragge #include <dev/qbus/ubavar.h> 100 1.1 ragge 101 1.2 ragge #include <dev/qbus/tsreg.h> 102 1.1 ragge 103 1.2 ragge #include "ioconf.h" 104 1.1 ragge 105 1.24 matt struct ts { 106 1.24 matt struct cmd cmd; /* command packet */ 107 1.24 matt struct chr chr; /* characteristics packet */ 108 1.24 matt struct status status; /* status packet */ 109 1.2 ragge }; 110 1.1 ragge 111 1.1 ragge /* 112 1.1 ragge * Software status, per controller. 113 1.1 ragge * also status per tape-unit, since only one unit per controller 114 1.1 ragge * (thus we have no struct ts_info) 115 1.1 ragge */ 116 1.24 matt struct ts_softc { 117 1.24 matt device_t sc_dev; /* Autoconf ... */ 118 1.24 matt struct uba_softc *sc_uh; /* the parent UBA */ 119 1.24 matt struct uba_unit sc_unit; /* Struct common for UBA to talk */ 120 1.24 matt struct evcnt sc_intrcnt; /* Interrupt counting */ 121 1.24 matt struct ubinfo sc_ui; /* mapping info for struct ts */ 122 1.24 matt struct uba_unit sc_uu; /* Struct for UBA to communicate */ 123 1.2 ragge bus_space_tag_t sc_iot; 124 1.2 ragge bus_addr_t sc_ioh; 125 1.2 ragge bus_dma_tag_t sc_dmat; 126 1.2 ragge bus_dmamap_t sc_dmam; 127 1.2 ragge volatile struct ts *sc_vts; /* Memory address of ts struct */ 128 1.24 matt struct ts *sc_bts; /* Unibus address of ts struct */ 129 1.2 ragge int sc_type; /* TS11 or TS05? */ 130 1.2 ragge short sc_waddr; /* Value to write to TSDB */ 131 1.24 matt struct bufq_state *sc_bufq; /* pending I/O requests */ 132 1.2 ragge 133 1.1 ragge short sc_mapped; /* Unibus map allocated ? */ 134 1.1 ragge short sc_state; /* see below: ST_xxx */ 135 1.1 ragge short sc_rtc; /* retry count for lcmd */ 136 1.1 ragge short sc_openf; /* lock against multiple opens */ 137 1.1 ragge short sc_liowf; /* last operation was write */ 138 1.24 matt struct buf ts_cbuf; /* internal cmd buffer (for ioctls) */ 139 1.1 ragge }; 140 1.1 ragge 141 1.2 ragge #define TS_WCSR(csr, val) \ 142 1.2 ragge bus_space_write_2(sc->sc_iot, sc->sc_ioh, csr, val) 143 1.2 ragge #define TS_RCSR(csr) \ 144 1.2 ragge bus_space_read_2(sc->sc_iot, sc->sc_ioh, csr) 145 1.2 ragge 146 1.2 ragge #define LOWORD(x) ((int)(x) & 0xffff) 147 1.2 ragge #define HIWORD(x) (((int)(x) >> 16) & 0x3f) 148 1.2 ragge 149 1.2 ragge #define TYPE_TS11 0 150 1.2 ragge #define TYPE_TS05 1 151 1.2 ragge #define TYPE_TU80 2 152 1.2 ragge 153 1.2 ragge #define TS_INVALID 0 154 1.2 ragge #define TS_INIT 1 155 1.2 ragge #define TS_RUNNING 2 156 1.2 ragge #define TS_FASTREPOS 3 157 1.2 ragge 158 1.2 ragge static void tsintr(void *); 159 1.2 ragge static void tsinit(struct ts_softc *); 160 1.2 ragge static void tscommand(struct ts_softc *, dev_t, int, int); 161 1.2 ragge static int tsstart(struct ts_softc *, int); 162 1.2 ragge static void tswchar(struct ts_softc *); 163 1.24 matt static bool tsreset(struct ts_softc *); 164 1.24 matt static int tsmatch(device_t, cfdata_t, void *); 165 1.24 matt static void tsattach(device_t, device_t, void *); 166 1.2 ragge static int tsready(struct uba_unit *); 167 1.2 ragge 168 1.24 matt CFATTACH_DECL_NEW(ts, sizeof(struct ts_softc), 169 1.9 thorpej tsmatch, tsattach, NULL, NULL); 170 1.5 gehenna 171 1.5 gehenna dev_type_open(tsopen); 172 1.5 gehenna dev_type_close(tsclose); 173 1.5 gehenna dev_type_read(tsread); 174 1.5 gehenna dev_type_write(tswrite); 175 1.5 gehenna dev_type_ioctl(tsioctl); 176 1.5 gehenna dev_type_strategy(tsstrategy); 177 1.5 gehenna dev_type_dump(tsdump); 178 1.5 gehenna 179 1.5 gehenna const struct bdevsw ts_bdevsw = { 180 1.29 dholland .d_open = tsopen, 181 1.29 dholland .d_close = tsclose, 182 1.29 dholland .d_strategy = tsstrategy, 183 1.29 dholland .d_ioctl = tsioctl, 184 1.29 dholland .d_dump = tsdump, 185 1.29 dholland .d_psize = nosize, 186 1.30 dholland .d_discard = nodiscard, 187 1.29 dholland .d_flag = D_TAPE 188 1.5 gehenna }; 189 1.5 gehenna 190 1.5 gehenna const struct cdevsw ts_cdevsw = { 191 1.29 dholland .d_open = tsopen, 192 1.29 dholland .d_close = tsclose, 193 1.29 dholland .d_read = tsread, 194 1.29 dholland .d_write = tswrite, 195 1.29 dholland .d_ioctl = tsioctl, 196 1.29 dholland .d_stop = nostop, 197 1.29 dholland .d_tty = notty, 198 1.29 dholland .d_poll = nopoll, 199 1.29 dholland .d_mmap = nommap, 200 1.29 dholland .d_kqfilter = nokqfilter, 201 1.31 dholland .d_discard = nodiscard, 202 1.29 dholland .d_flag = D_TAPE 203 1.1 ragge }; 204 1.1 ragge 205 1.13 simonb /* Bits in minor device */ 206 1.1 ragge #define TS_UNIT(dev) (minor(dev)&03) 207 1.1 ragge #define TS_HIDENSITY 010 208 1.1 ragge 209 1.1 ragge #define TS_PRI LOG_INFO 210 1.1 ragge 211 1.1 ragge 212 1.1 ragge /* 213 1.2 ragge * Probe for device. If found, try to raise an interrupt. 214 1.1 ragge */ 215 1.2 ragge int 216 1.24 matt tsmatch(device_t parent, cfdata_t match, void *aux) 217 1.2 ragge { 218 1.2 ragge struct ts_softc ssc; 219 1.2 ragge struct ts_softc *sc = &ssc; 220 1.2 ragge struct uba_attach_args *ua = aux; 221 1.2 ragge int i; 222 1.1 ragge 223 1.2 ragge sc->sc_iot = ua->ua_iot; 224 1.2 ragge sc->sc_ioh = ua->ua_ioh; 225 1.2 ragge sc->sc_mapped = 0; 226 1.24 matt sc->sc_uh = device_private(parent); 227 1.1 ragge 228 1.2 ragge /* Try to reset the device */ 229 1.24 matt for (i = 0; i < 3; i++) { 230 1.24 matt if (tsreset(sc)) 231 1.2 ragge break; 232 1.24 matt } 233 1.2 ragge 234 1.2 ragge if (i == 3) 235 1.2 ragge return 0; 236 1.1 ragge 237 1.2 ragge tsinit(sc); 238 1.2 ragge tswchar(sc); /* write charact. to enable interrupts */ 239 1.2 ragge /* completion of this will raise the intr. */ 240 1.1 ragge 241 1.2 ragge DELAY(1000000); /* Wait for interrupt */ 242 1.24 matt ubmemfree(sc->sc_uh, &sc->sc_ui); 243 1.2 ragge return 1; 244 1.1 ragge } 245 1.1 ragge 246 1.1 ragge /* 247 1.1 ragge */ 248 1.2 ragge void 249 1.24 matt tsattach(device_t parent, device_t self, void *aux) 250 1.1 ragge { 251 1.17 thorpej struct ts_softc *sc = device_private(self); 252 1.2 ragge struct uba_attach_args *ua = aux; 253 1.2 ragge int error; 254 1.24 matt const char *t; 255 1.2 ragge 256 1.24 matt sc->sc_dev = self; 257 1.24 matt sc->sc_uh = device_private(parent); 258 1.2 ragge sc->sc_iot = ua->ua_iot; 259 1.2 ragge sc->sc_ioh = ua->ua_ioh; 260 1.2 ragge sc->sc_dmat = ua->ua_dmat; 261 1.13 simonb 262 1.24 matt sc->sc_uu.uu_dev = self; 263 1.2 ragge sc->sc_uu.uu_ready = tsready; 264 1.1 ragge 265 1.2 ragge tsinit(sc); /* reset and map */ 266 1.1 ragge 267 1.24 matt error = bus_dmamap_create(sc->sc_dmat, (64*1024), 16, (64*1024), 268 1.24 matt 0, BUS_DMA_NOWAIT, &sc->sc_dmam); 269 1.24 matt if (error) { 270 1.24 matt aprint_error(": failed create DMA map %d\n", error); 271 1.24 matt return; 272 1.24 matt } 273 1.1 ragge 274 1.14 yamt bufq_alloc(&sc->sc_bufq, "fcfs", 0); 275 1.1 ragge 276 1.1 ragge /* 277 1.2 ragge * write the characteristics (again) 278 1.1 ragge */ 279 1.2 ragge sc->sc_state = TS_INIT; /* tsintr() checks this ... */ 280 1.2 ragge tswchar(sc); 281 1.24 matt if (tsleep(sc, PRIBIO, "tsattach", 100)) { 282 1.24 matt aprint_error(": failed SET CHARACTERISTICS\n"); 283 1.24 matt return; 284 1.24 matt } 285 1.2 ragge 286 1.2 ragge sc->sc_state = TS_RUNNING; 287 1.24 matt if (sc->sc_uh->uh_type == UBA_UBA) { 288 1.2 ragge if (sc->sc_vts->status.xst2 & TS_SF_TU80) { 289 1.2 ragge sc->sc_type = TYPE_TU80; 290 1.2 ragge t = "TU80"; 291 1.2 ragge } else { 292 1.2 ragge sc->sc_type = TYPE_TS11; 293 1.2 ragge t = "TS11"; 294 1.1 ragge } 295 1.2 ragge } else { 296 1.2 ragge sc->sc_type = TYPE_TS05; 297 1.2 ragge t = "TS05"; 298 1.1 ragge } 299 1.1 ragge 300 1.24 matt aprint_normal(": %s\n", t); 301 1.24 matt aprint_normal_dev(sc->sc_dev, 302 1.24 matt "rev %d, extended features %s, transport %s\n", 303 1.24 matt (sc->sc_vts->status.xst2 & TS_SF_MCRL) >> 2, 304 1.24 matt (sc->sc_vts->status.xst2 & TS_SF_EFES ? "enabled" : "disabled"), 305 1.24 matt (TS_RCSR(TSSR) & TS_OFL ? "offline" : "online")); 306 1.2 ragge 307 1.2 ragge uba_intr_establish(ua->ua_icookie, ua->ua_cvec, tsintr, 308 1.2 ragge sc, &sc->sc_intrcnt); 309 1.2 ragge evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt, 310 1.24 matt device_xname(sc->sc_dev), "intr"); 311 1.2 ragge } 312 1.2 ragge 313 1.2 ragge /* 314 1.2 ragge * Initialize a TS device. Set up UBA mapping registers, 315 1.2 ragge * initialize data structures, what else ??? 316 1.2 ragge */ 317 1.13 simonb void 318 1.2 ragge tsinit(struct ts_softc *sc) 319 1.2 ragge { 320 1.2 ragge if (sc->sc_mapped == 0) { 321 1.2 ragge 322 1.2 ragge /* 323 1.2 ragge * Map the communications area and command and message 324 1.2 ragge * buffer into Unibus address space. 325 1.2 ragge */ 326 1.2 ragge sc->sc_ui.ui_size = sizeof(struct ts); 327 1.24 matt if (ubmemalloc(sc->sc_uh, &sc->sc_ui, UBA_CANTWAIT)) 328 1.2 ragge return; 329 1.2 ragge sc->sc_vts = (void *)sc->sc_ui.ui_vaddr; 330 1.2 ragge sc->sc_bts = (void *)sc->sc_ui.ui_baddr; 331 1.2 ragge sc->sc_waddr = sc->sc_ui.ui_baddr | 332 1.2 ragge ((sc->sc_ui.ui_baddr >> 16) & 3); 333 1.2 ragge sc->sc_mapped = 1; 334 1.2 ragge } 335 1.2 ragge tsreset(sc); 336 1.1 ragge } 337 1.1 ragge 338 1.13 simonb /* 339 1.1 ragge * Execute a (ioctl) command on the tape drive a specified number of times. 340 1.1 ragge * This routine sets up a buffer and calls the strategy routine which 341 1.1 ragge * issues the command to the controller. 342 1.1 ragge */ 343 1.1 ragge void 344 1.2 ragge tscommand(struct ts_softc *sc, dev_t dev, int cmd, int count) 345 1.1 ragge { 346 1.2 ragge struct buf *bp; 347 1.1 ragge 348 1.2 ragge #ifdef TSDEBUG 349 1.2 ragge printf("tscommand (%x, %d)\n", cmd, count); 350 1.2 ragge #endif 351 1.2 ragge 352 1.2 ragge bp = &sc->ts_cbuf; 353 1.1 ragge 354 1.22 ad mutex_enter(&bufcache_lock); 355 1.22 ad while (bp->b_cflags & BC_BUSY) { 356 1.1 ragge /* 357 1.22 ad * This special check is because BC_BUSY never 358 1.1 ragge * gets cleared in the non-waiting rewind case. ??? 359 1.1 ragge */ 360 1.22 ad if (bp->b_bcount == 0 && (bp->b_oflags & BO_DONE)) 361 1.1 ragge break; 362 1.23 ad if (bbusy(bp, false, 0, NULL) == 0) 363 1.23 ad break; 364 1.1 ragge /* check MOT-flag !!! */ 365 1.1 ragge } 366 1.22 ad bp->b_flags = B_READ; 367 1.22 ad mutex_exit(&bufcache_lock); 368 1.1 ragge 369 1.1 ragge /* 370 1.1 ragge * Load the buffer. The b_count field gets used to hold the command 371 1.36 andvar * count. the b_resid field gets used to hold the command mnemonic. 372 1.1 ragge * These 2 fields are "known" to be "safe" to use for this purpose. 373 1.1 ragge * (Most other drivers also use these fields in this way.) 374 1.1 ragge */ 375 1.1 ragge bp->b_dev = dev; 376 1.1 ragge bp->b_bcount = count; 377 1.1 ragge bp->b_resid = cmd; 378 1.1 ragge bp->b_blkno = 0; 379 1.22 ad bp->b_oflags = 0; 380 1.22 ad bp->b_objlock = &buffer_lock; 381 1.2 ragge tsstrategy(bp); 382 1.1 ragge /* 383 1.1 ragge * In case of rewind from close, don't wait. 384 1.1 ragge * This is the only case where count can be 0. 385 1.1 ragge */ 386 1.2 ragge if (count == 0) 387 1.1 ragge return; 388 1.2 ragge biowait(bp); 389 1.22 ad mutex_enter(&bufcache_lock); 390 1.33 ad cv_broadcast(&bp->b_busy); 391 1.22 ad bp->b_cflags = 0; 392 1.22 ad mutex_exit(&bufcache_lock); 393 1.1 ragge } 394 1.1 ragge 395 1.1 ragge /* 396 1.1 ragge * Start an I/O operation on TS05 controller 397 1.1 ragge */ 398 1.1 ragge int 399 1.2 ragge tsstart(struct ts_softc *sc, int isloaded) 400 1.1 ragge { 401 1.2 ragge struct buf *bp; 402 1.1 ragge int cmd; 403 1.1 ragge 404 1.27 yamt bp = bufq_peek(sc->sc_bufq); 405 1.14 yamt if (bp == NULL) { 406 1.2 ragge return 0; 407 1.14 yamt } 408 1.2 ragge #ifdef TSDEBUG 409 1.2 ragge printf("buf: %p bcount %ld blkno %d\n", bp, bp->b_bcount, bp->b_blkno); 410 1.2 ragge #endif 411 1.1 ragge /* 412 1.1 ragge * Check if command is an ioctl or not (ie. read or write). 413 1.1 ragge * If it's an ioctl then just set the flags for later use; 414 1.1 ragge * For other commands attempt to setup a buffer pointer. 415 1.1 ragge */ 416 1.2 ragge if (bp == &sc->ts_cbuf) { 417 1.1 ragge switch ((int)bp->b_resid) { 418 1.1 ragge case MTWEOF: 419 1.1 ragge cmd = TS_CMD_WTM; 420 1.1 ragge break; 421 1.1 ragge case MTFSF: 422 1.1 ragge cmd = TS_CMD_STMF; 423 1.2 ragge sc->sc_vts->cmd.cw1 = bp->b_bcount; 424 1.1 ragge break; 425 1.1 ragge case MTBSF: 426 1.13 simonb cmd = TS_CMD_STMR; 427 1.2 ragge sc->sc_vts->cmd.cw1 = bp->b_bcount; 428 1.1 ragge break; 429 1.1 ragge case MTFSR: 430 1.1 ragge cmd = TS_CMD_SRF; 431 1.2 ragge sc->sc_vts->cmd.cw1 = bp->b_bcount; 432 1.1 ragge break; 433 1.1 ragge case MTBSR: 434 1.1 ragge cmd = TS_CMD_SRR; 435 1.2 ragge sc->sc_vts->cmd.cw1 = bp->b_bcount; 436 1.1 ragge break; 437 1.1 ragge case MTREW: 438 1.1 ragge cmd = TS_CMD_RWND; 439 1.1 ragge break; 440 1.1 ragge case MTOFFL: 441 1.1 ragge cmd = TS_CMD_RWUL; 442 1.1 ragge break; 443 1.1 ragge case MTNOP: 444 1.1 ragge cmd = TS_CMD_STAT; 445 1.1 ragge break; 446 1.1 ragge default: 447 1.24 matt aprint_error_dev(sc->sc_dev, "bad ioctl %d\n", 448 1.1 ragge (int)bp->b_resid); 449 1.1 ragge /* Need a no-op. get status */ 450 1.1 ragge cmd = TS_CMD_STAT; 451 1.1 ragge } /* end switch (bp->b_resid) */ 452 1.2 ragge } else { 453 1.2 ragge if (isloaded == 0) { 454 1.2 ragge /* 455 1.2 ragge * now we try to map the buffer into uba map space (???) 456 1.2 ragge */ 457 1.2 ragge if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, 458 1.2 ragge bp->b_data, 459 1.2 ragge bp->b_bcount, bp->b_proc, BUS_DMA_NOWAIT)) { 460 1.2 ragge uba_enqueue(&sc->sc_uu); 461 1.2 ragge return 0; 462 1.2 ragge } 463 1.2 ragge sc->sc_rtc = 0; 464 1.2 ragge } 465 1.2 ragge sc->sc_vts->cmd.cw1 = LOWORD(sc->sc_dmam->dm_segs[0].ds_addr); 466 1.2 ragge sc->sc_vts->cmd.cw2 = HIWORD(sc->sc_dmam->dm_segs[0].ds_addr); 467 1.2 ragge sc->sc_vts->cmd.cw3 = bp->b_bcount; 468 1.2 ragge bp->b_error = 0; /* Used for error count */ 469 1.2 ragge #ifdef TSDEBUG 470 1.2 ragge printf("tsstart-1: err %d\n", bp->b_error); 471 1.2 ragge #endif 472 1.2 ragge if (bp->b_flags & B_READ) 473 1.1 ragge cmd = TS_CMD_RNF; 474 1.2 ragge else 475 1.1 ragge cmd = TS_CMD_WD; 476 1.1 ragge } 477 1.1 ragge 478 1.1 ragge /* 479 1.1 ragge * Now that the command-buffer is setup, give it to the controller 480 1.1 ragge */ 481 1.2 ragge sc->sc_vts->cmd.cmdr = TS_CF_ACK | TS_CF_IE | cmd; 482 1.2 ragge #ifdef TSDEBUG 483 1.2 ragge printf("tsstart: sending cmdr %x\n", sc->sc_vts->cmd.cmdr); 484 1.2 ragge #endif 485 1.2 ragge TS_WCSR(TSDB, sc->sc_waddr); 486 1.24 matt return 1; 487 1.1 ragge } 488 1.1 ragge 489 1.1 ragge /* 490 1.2 ragge * Called when there are free uba resources. 491 1.1 ragge */ 492 1.2 ragge int 493 1.2 ragge tsready(struct uba_unit *uu) 494 1.1 ragge { 495 1.24 matt struct ts_softc *sc = device_private(uu->uu_dev); 496 1.27 yamt struct buf *bp = bufq_peek(sc->sc_bufq); 497 1.1 ragge 498 1.2 ragge if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, bp->b_data, 499 1.2 ragge bp->b_bcount, bp->b_proc, BUS_DMA_NOWAIT)) 500 1.2 ragge return 0; 501 1.1 ragge 502 1.2 ragge tsstart(sc, 1); 503 1.2 ragge return 1; 504 1.1 ragge } 505 1.1 ragge 506 1.1 ragge /* 507 1.2 ragge * initialize the controller by sending WRITE CHARACTERISTICS command. 508 1.2 ragge * contents of command- and message-buffer are assembled during this 509 1.13 simonb * function. 510 1.1 ragge */ 511 1.13 simonb void 512 1.2 ragge tswchar(struct ts_softc *sc) 513 1.1 ragge { 514 1.1 ragge /* 515 1.2 ragge * assemble and send "WRITE CHARACTERISTICS" command 516 1.1 ragge */ 517 1.1 ragge 518 1.2 ragge sc->sc_vts->cmd.cmdr = TS_CF_ACK | TS_CF_IE | TS_CMD_WCHAR; 519 1.2 ragge sc->sc_vts->cmd.cw1 = LOWORD(&sc->sc_bts->chr); 520 1.2 ragge sc->sc_vts->cmd.cw2 = HIWORD(&sc->sc_bts->chr); 521 1.2 ragge sc->sc_vts->cmd.cw3 = 010; /* size of charact.-data */ 522 1.2 ragge 523 1.2 ragge sc->sc_vts->chr.sadrl = LOWORD(&sc->sc_bts->status); 524 1.2 ragge sc->sc_vts->chr.sadrh = HIWORD(&sc->sc_bts->status); 525 1.2 ragge sc->sc_vts->chr.onesix = (sc->sc_type == TYPE_TS05 ? 020 : 016); 526 1.2 ragge sc->sc_vts->chr.chrw = TS_WC_ESS; 527 1.2 ragge sc->sc_vts->chr.xchrw = TS_WCX_HSP|TS_WCX_RBUF|TS_WCX_WBUF; 528 1.2 ragge 529 1.2 ragge TS_WCSR(TSDB, sc->sc_waddr); 530 1.1 ragge } 531 1.1 ragge 532 1.1 ragge /* 533 1.2 ragge * Reset the TS11. Return 1 if failed, 0 if succeeded. 534 1.1 ragge */ 535 1.24 matt bool 536 1.2 ragge tsreset(struct ts_softc *sc) 537 1.1 ragge { 538 1.2 ragge int timeout; 539 1.1 ragge 540 1.1 ragge /* 541 1.2 ragge * reset ctlr by writing into TSSR, then write characteristics 542 1.1 ragge */ 543 1.13 simonb timeout = 0; /* timeout in 10 seconds */ 544 1.2 ragge TS_WCSR(TSSR, 0); /* start initialization */ 545 1.2 ragge while ((TS_RCSR(TSSR) & TS_SSR) == 0) { 546 1.1 ragge DELAY(10000); 547 1.2 ragge if (timeout++ > 1000) 548 1.24 matt return false; 549 1.2 ragge } 550 1.24 matt return true; 551 1.1 ragge } 552 1.1 ragge 553 1.2 ragge static void 554 1.2 ragge prtstat(struct ts_softc *sc, int sr) 555 1.1 ragge { 556 1.2 ragge char buf[100]; 557 1.1 ragge 558 1.26 christos snprintb(buf, sizeof(buf), TS_TSSR_BITS, sr); 559 1.24 matt aprint_normal_dev(sc->sc_dev, "TSSR=%s\n", buf); 560 1.26 christos snprintb(buf, sizeof(buf), TS_XST0_BITS, sc->sc_vts->status.xst0); 561 1.24 matt aprint_normal_dev(sc->sc_dev, "XST0=%s\n", buf); 562 1.1 ragge } 563 1.1 ragge 564 1.1 ragge /* 565 1.1 ragge * TSV05/TS05 interrupt routine 566 1.1 ragge */ 567 1.2 ragge static void 568 1.2 ragge tsintr(void *arg) 569 1.1 ragge { 570 1.2 ragge struct ts_softc *sc = arg; 571 1.2 ragge struct buf *bp; 572 1.1 ragge 573 1.2 ragge unsigned short sr = TS_RCSR(TSSR); /* save TSSR */ 574 1.2 ragge unsigned short mh = sc->sc_vts->status.hdr; /* and msg-header */ 575 1.1 ragge /* clear the message header ??? */ 576 1.1 ragge 577 1.2 ragge short ccode = sc->sc_vts->cmd.cmdr & TS_CF_CCODE; 578 1.1 ragge 579 1.27 yamt bp = bufq_peek(sc->sc_bufq); 580 1.2 ragge #ifdef TSDEBUG 581 1.1 ragge { 582 1.2 ragge char buf[100]; 583 1.26 christos snprintb(buf, sizeof(buf), TS_TSSR_BITS, sr); 584 1.2 ragge printf("tsintr: sr %x mh %x\n", sr, mh); 585 1.2 ragge printf("srbits: %s\n", buf); 586 1.1 ragge } 587 1.1 ragge #endif 588 1.1 ragge /* 589 1.1 ragge * There are two different things which can (and should) be checked: 590 1.1 ragge * the actual (internal) state and the device's result (tssr/msg.hdr) 591 1.13 simonb * 592 1.1 ragge * For each state there's only one "normal" interrupt. Anything else 593 1.1 ragge * has to be checked more intensively. Thus in a first run according 594 1.1 ragge * to the internal state the expected interrupt is checked/handled. 595 1.1 ragge * 596 1.1 ragge * In a second run the remaining (not yet handled) interrupts are 597 1.1 ragge * checked according to the drive's result. 598 1.1 ragge */ 599 1.1 ragge switch (sc->sc_state) { 600 1.1 ragge 601 1.2 ragge case TS_INVALID: 602 1.1 ragge /* 603 1.1 ragge * Ignore unsolicited interrupts. 604 1.1 ragge */ 605 1.13 simonb log(LOG_WARNING, "%s: stray intr [%x,%x]\n", 606 1.24 matt device_xname(sc->sc_dev), sr, mh); 607 1.1 ragge return; 608 1.1 ragge 609 1.2 ragge case TS_INIT: 610 1.1 ragge /* 611 1.2 ragge * Init phase ready. 612 1.1 ragge */ 613 1.2 ragge wakeup(sc); 614 1.1 ragge return; 615 1.1 ragge 616 1.2 ragge case TS_RUNNING: 617 1.2 ragge case TS_FASTREPOS: 618 1.1 ragge /* 619 1.1 ragge * Here we expect interrupts indicating the end of 620 1.1 ragge * commands or indicating problems. 621 1.1 ragge */ 622 1.1 ragge /* 623 1.1 ragge * Anything else is handled outside this switch ... 624 1.1 ragge */ 625 1.1 ragge break; 626 1.1 ragge 627 1.1 ragge default: 628 1.24 matt aprint_error_dev(sc->sc_dev, 629 1.24 matt "unexpected interrupt during state %d [%x,%x]\n", 630 1.24 matt sc->sc_state, sr, mh); 631 1.1 ragge return; 632 1.1 ragge } 633 1.1 ragge 634 1.1 ragge /* 635 1.1 ragge * now we check the termination class. 636 1.1 ragge */ 637 1.1 ragge switch (sr & TS_TC) { 638 1.1 ragge 639 1.1 ragge case TS_TC_NORM: 640 1.1 ragge /* 641 1.1 ragge * Normal termination -- The operation is completed 642 1.36 andvar * without incident. 643 1.1 ragge */ 644 1.2 ragge if (sc->sc_state == TS_FASTREPOS) { 645 1.2 ragge #ifdef TSDEBUG 646 1.2 ragge printf("Fast repos interrupt\n"); 647 1.2 ragge #endif 648 1.2 ragge /* Fast repos succeeded, start normal data xfer */ 649 1.2 ragge sc->sc_state = TS_RUNNING; 650 1.2 ragge tsstart(sc, 1); 651 1.2 ragge return; 652 1.2 ragge } 653 1.1 ragge sc->sc_liowf = (ccode == TS_CC_WRITE); 654 1.2 ragge break; 655 1.1 ragge 656 1.1 ragge case TS_TC_ATTN: 657 1.1 ragge /* 658 1.1 ragge * Attention condition -- this code indicates that the 659 1.1 ragge * drive has undergone a status change, such as going 660 1.1 ragge * off-line or coming on-line. 661 1.1 ragge * (Without EAI enabled, no Attention interrupts occur. 662 1.1 ragge * drive status changes are signaled by the VCK flag.) 663 1.1 ragge */ 664 1.1 ragge return; 665 1.1 ragge 666 1.1 ragge case TS_TC_TSA: 667 1.13 simonb /* 668 1.1 ragge * Tape Status Alert -- A status condition is encountered 669 1.1 ragge * that may have significance to the program. Bits of 670 1.1 ragge * interest in the extended status registers include 671 1.1 ragge * TMK, EOT and RLL. 672 1.1 ragge */ 673 1.2 ragge #ifdef TSDEBUG 674 1.2 ragge { 675 1.2 ragge char buf[100]; 676 1.26 christos snprintb(buf, sizeof(buf), 677 1.26 christos TS_XST0_BITS, sc->sc_vts->status.xst0); 678 1.2 ragge printf("TSA: sr %x bits %s\n", 679 1.2 ragge sc->sc_vts->status.xst0, buf); 680 1.2 ragge } 681 1.2 ragge #endif 682 1.2 ragge if (sc->sc_vts->status.xst0 & TS_SF_TMK) { 683 1.24 matt #ifdef TSDEBUG 684 1.24 matt printf(("Tape Mark detected")); 685 1.24 matt #endif 686 1.2 ragge /* Read to end-of-file. No error. */ 687 1.2 ragge break; 688 1.2 ragge } 689 1.2 ragge if (sc->sc_vts->status.xst0 & TS_SF_EOT) { 690 1.2 ragge /* End of tape. Bad. */ 691 1.2 ragge #ifdef TSDEBUG 692 1.2 ragge printf("TS_TC_TSA: EOT\n"); 693 1.2 ragge #endif 694 1.24 matt if (bp != NULL) 695 1.24 matt bp->b_error = EIO; 696 1.2 ragge break; 697 1.2 ragge } 698 1.2 ragge if (sc->sc_vts->status.xst0 & TS_SF_RLS) 699 1.2 ragge break; 700 1.2 ragge #ifndef TSDEBUG 701 1.2 ragge { 702 1.2 ragge char buf[100]; 703 1.26 christos snprintb(buf, sizeof(buf), 704 1.26 christos TS_XST0_BITS, sc->sc_vts->status.xst0); 705 1.2 ragge printf("TSA: sr %x bits %s\n", 706 1.2 ragge sc->sc_vts->status.xst0, buf); 707 1.1 ragge } 708 1.2 ragge #endif 709 1.1 ragge break; 710 1.1 ragge 711 1.13 simonb case TS_TC_FR: 712 1.1 ragge /* 713 1.1 ragge * Function Reject -- The specified function was not 714 1.1 ragge * initiated. Bits of interest include OFL, VCK, BOT, 715 1.1 ragge * WLE, ILC and ILA. 716 1.1 ragge */ 717 1.2 ragge if (sr & TS_OFL) 718 1.2 ragge printf("tape is off-line.\n"); 719 1.2 ragge #ifdef TSDEBUG 720 1.2 ragge { 721 1.2 ragge char buf[100]; 722 1.26 christos snprintb(buf, sizeof(buf), 723 1.26 christos TS_XST0_BITS, sc->sc_vts->status.xst0); 724 1.2 ragge printf("FR: sr %x bits %s\n", 725 1.2 ragge sc->sc_vts->status.xst0, buf); 726 1.2 ragge } 727 1.2 ragge #endif 728 1.2 ragge if (sc->sc_vts->status.xst0 & TS_SF_VCK) 729 1.2 ragge printf("Volume check\n"); 730 1.2 ragge if (sc->sc_vts->status.xst0 & TS_SF_BOT) 731 1.2 ragge printf("Start of tape.\n"); 732 1.2 ragge if (sc->sc_vts->status.xst0 & TS_SF_WLE) 733 1.2 ragge printf("Write Lock Error\n"); 734 1.2 ragge if (sc->sc_vts->status.xst0 & TS_SF_EOT) 735 1.2 ragge printf("End of tape.\n"); 736 1.1 ragge break; 737 1.1 ragge 738 1.1 ragge case TS_TC_TPD: 739 1.1 ragge /* 740 1.1 ragge * Recoverable Error -- Tape position is a record beyond 741 1.1 ragge * what its position was when the function was initiated. 742 1.1 ragge * Suggested recovery procedure is to log the error and 743 1.1 ragge * issue the appropriate retry command. 744 1.2 ragge * 745 1.2 ragge * Do a fast repositioning one record back. 746 1.1 ragge */ 747 1.2 ragge sc->sc_state = TS_FASTREPOS; 748 1.2 ragge #ifdef TSDEBUG 749 1.2 ragge printf("TS_TC_TPD: errcnt %d\n", sc->sc_rtc); 750 1.2 ragge #endif 751 1.2 ragge if (sc->sc_rtc++ == 8) { 752 1.24 matt aprint_error_dev(sc->sc_dev, "failed 8 retries\n"); 753 1.2 ragge prtstat(sc, sr); 754 1.24 matt if (bp != NULL) 755 1.24 matt bp->b_error = EIO; 756 1.2 ragge break; 757 1.1 ragge } 758 1.2 ragge sc->sc_vts->cmd.cmdr = TS_CF_ACK | TS_CF_IE | TS_CMD_SRR; 759 1.2 ragge sc->sc_vts->cmd.cw1 = 1; 760 1.2 ragge TS_WCSR(TSDB, sc->sc_waddr); 761 1.2 ragge return; 762 1.2 ragge 763 1.1 ragge case TS_TC_TNM: 764 1.1 ragge /* 765 1.1 ragge * Recoverable Error -- Tape position has not changed. 766 1.1 ragge * Suggested recovery procedure is to log the error and 767 1.1 ragge * reissue the original command. 768 1.1 ragge */ 769 1.2 ragge if (sc->sc_rtc++ == 8) { 770 1.24 matt aprint_error_dev(sc->sc_dev, "failed 8 retries\n"); 771 1.2 ragge prtstat(sc, sr); 772 1.24 matt if (bp != NULL) 773 1.24 matt bp->b_error = EIO; 774 1.2 ragge break; 775 1.1 ragge } 776 1.2 ragge tsstart(sc, 1); 777 1.2 ragge return; 778 1.1 ragge 779 1.1 ragge case TS_TC_TPL: 780 1.1 ragge /* 781 1.1 ragge * Unrecoverable Error -- Tape position has been lost. 782 1.1 ragge * No valid recovery procedures exist unless the tape 783 1.1 ragge * has labels or sequence numbers. 784 1.1 ragge */ 785 1.24 matt aprint_error_dev(sc->sc_dev, "tape position lost\n"); 786 1.24 matt if (bp != NULL) 787 1.24 matt bp->b_error = EIO; 788 1.1 ragge break; 789 1.1 ragge 790 1.1 ragge case TS_TC_FCE: 791 1.1 ragge /* 792 1.34 msaitoh * Fatal subsystem Error -- The subsystem is incapable 793 1.1 ragge * of properly performing commands, or at least its 794 1.13 simonb * integrity is seriously questionable. Refer to the 795 1.1 ragge * fatal class code field in the TSSR register for 796 1.1 ragge * additional information on the type of fatal error. 797 1.1 ragge */ 798 1.24 matt aprint_error_dev(sc->sc_dev, "fatal controller error\n"); 799 1.2 ragge prtstat(sc, sr); 800 1.2 ragge break; 801 1.1 ragge 802 1.1 ragge default: 803 1.24 matt aprint_error_dev(sc->sc_dev, 804 1.24 matt "error 0x%x, resetting controller\n", sr & TS_TC); 805 1.2 ragge tsreset(sc); 806 1.1 ragge } 807 1.27 yamt if ((bp = bufq_get(sc->sc_bufq)) != NULL) { 808 1.2 ragge #ifdef TSDEBUG 809 1.27 yamt printf("tsintr2: que %p\n", bufq_peek(sc->sc_bufq)); 810 1.2 ragge #endif 811 1.2 ragge if (bp != &sc->ts_cbuf) { /* no ioctl */ 812 1.2 ragge bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam); 813 1.24 matt uba_done(sc->sc_uh); 814 1.2 ragge } 815 1.2 ragge bp->b_resid = sc->sc_vts->status.rbpcr; 816 1.1 ragge biodone (bp); 817 1.1 ragge } 818 1.2 ragge tsstart(sc, 0); 819 1.1 ragge } 820 1.1 ragge 821 1.1 ragge 822 1.1 ragge /* 823 1.1 ragge * Open a ts device and set the unit online. If the controller is not 824 1.1 ragge * in the run state, call init to initialize the ts controller first. 825 1.1 ragge */ 826 1.1 ragge int 827 1.24 matt tsopen(dev_t dev, int flag, int type, struct lwp *l) 828 1.1 ragge { 829 1.24 matt struct ts_softc *sc = device_lookup_private(&ts_cd, TS_UNIT(dev)); 830 1.1 ragge 831 1.24 matt if (sc == NULL) 832 1.1 ragge return ENXIO; 833 1.1 ragge 834 1.2 ragge if (sc->sc_state < TS_RUNNING) 835 1.2 ragge return ENXIO; 836 1.2 ragge 837 1.1 ragge if (sc->sc_openf) 838 1.1 ragge return EBUSY; 839 1.1 ragge sc->sc_openf = 1; 840 1.1 ragge 841 1.1 ragge /* 842 1.1 ragge * check if transport is really online. 843 1.1 ragge * (without attention-interrupts enabled, we really don't know 844 1.1 ragge * the actual state of the transport. Thus we call get-status 845 1.1 ragge * (ie. MTNOP) once and check the actual status.) 846 1.1 ragge */ 847 1.2 ragge if (TS_RCSR(TSSR) & TS_OFL) { 848 1.24 matt uprintf("%s: transport is offline.\n", device_xname(sc->sc_dev)); 849 1.1 ragge sc->sc_openf = 0; 850 1.1 ragge return EIO; /* transport is offline */ 851 1.1 ragge } 852 1.2 ragge tscommand(sc, dev, MTNOP, 1); 853 1.2 ragge if ((flag & FWRITE) && (sc->sc_vts->status.xst0 & TS_SF_WLK)) { 854 1.24 matt uprintf("%s: no write ring.\n", device_xname(sc->sc_dev)); 855 1.2 ragge sc->sc_openf = 0; 856 1.2 ragge return EROFS; 857 1.2 ragge } 858 1.2 ragge if (sc->sc_vts->status.xst0 & TS_SF_VCK) { 859 1.2 ragge sc->sc_vts->cmd.cmdr = TS_CF_CVC|TS_CF_ACK; 860 1.2 ragge TS_WCSR(TSDB, sc->sc_waddr); 861 1.2 ragge } 862 1.2 ragge tscommand(sc, dev, MTNOP, 1); 863 1.2 ragge #ifdef TSDEBUG 864 1.2 ragge { 865 1.2 ragge char buf[100]; 866 1.26 christos snprintb(buf, sizeof(buf), 867 1.26 christos TS_XST0_BITS, sc->sc_vts->status.xst0); 868 1.2 ragge printf("tsopen: xst0 %s\n", buf); 869 1.2 ragge } 870 1.2 ragge #endif 871 1.1 ragge sc->sc_liowf = 0; 872 1.1 ragge return 0; 873 1.1 ragge } 874 1.1 ragge 875 1.1 ragge 876 1.1 ragge /* 877 1.1 ragge * Close tape device. 878 1.1 ragge * 879 1.1 ragge * If tape was open for writing or last operation was 880 1.1 ragge * a write, then write two EOF's and backspace over the last one. 881 1.1 ragge * Unless this is a non-rewinding special file, rewind the tape. 882 1.1 ragge * 883 1.1 ragge * Make the tape available to others, by clearing openf flag. 884 1.1 ragge */ 885 1.1 ragge int 886 1.24 matt tsclose(dev_t dev, int flag, int type, struct lwp *l) 887 1.1 ragge { 888 1.24 matt struct ts_softc *sc = device_lookup_private(&ts_cd, TS_UNIT(dev)); 889 1.1 ragge 890 1.1 ragge if (flag == FWRITE || ((flag & FWRITE) && sc->sc_liowf)) { 891 1.13 simonb /* 892 1.1 ragge * We are writing two tape marks (EOT), but place the tape 893 1.1 ragge * before the second one, so that another write operation 894 1.1 ragge * will overwrite the second one and leave and EOF-mark. 895 1.1 ragge */ 896 1.2 ragge tscommand(sc, dev, MTWEOF, 1); /* Write Tape Mark */ 897 1.2 ragge tscommand(sc, dev, MTWEOF, 1); /* Write Tape Mark */ 898 1.2 ragge tscommand(sc, dev, MTBSF, 1); /* Skip Tape Marks Reverse */ 899 1.1 ragge } 900 1.1 ragge 901 1.1 ragge if ((dev & T_NOREWIND) == 0) 902 1.2 ragge tscommand(sc, dev, MTREW, 0); 903 1.1 ragge 904 1.1 ragge sc->sc_openf = 0; 905 1.1 ragge sc->sc_liowf = 0; 906 1.1 ragge return 0; 907 1.1 ragge } 908 1.1 ragge 909 1.1 ragge 910 1.1 ragge /* 911 1.1 ragge * Manage buffers and perform block mode read and write operations. 912 1.1 ragge */ 913 1.1 ragge void 914 1.2 ragge tsstrategy(struct buf *bp) 915 1.1 ragge { 916 1.24 matt struct ts_softc *sc = device_lookup_private(&ts_cd, TS_UNIT(bp->b_dev)); 917 1.24 matt bool empty; 918 1.24 matt int s; 919 1.1 ragge 920 1.2 ragge #ifdef TSDEBUG 921 1.2 ragge printf("buf: %p bcount %ld blkno %d\n", bp, bp->b_bcount, bp->b_blkno); 922 1.2 ragge #endif 923 1.1 ragge s = splbio (); 924 1.27 yamt empty = (bufq_peek(sc->sc_bufq) == NULL); 925 1.27 yamt bufq_put(sc->sc_bufq, bp); 926 1.2 ragge if (empty) 927 1.2 ragge tsstart(sc, 0); 928 1.1 ragge splx(s); 929 1.1 ragge } 930 1.1 ragge 931 1.1 ragge 932 1.1 ragge /* 933 1.1 ragge * Catch ioctl commands, and call the "command" routine to do them. 934 1.1 ragge */ 935 1.1 ragge int 936 1.24 matt tsioctl(dev_t dev, 937 1.24 matt u_long cmd, 938 1.24 matt void *data, 939 1.24 matt int flag, 940 1.24 matt struct lwp *l) 941 1.1 ragge { 942 1.2 ragge struct buf *bp; 943 1.24 matt struct ts_softc * const sc = device_lookup_private(&ts_cd, TS_UNIT(dev)); 944 1.2 ragge struct mtop *mtop; /* mag tape cmd op to perform */ 945 1.2 ragge struct mtget *mtget; /* mag tape struct to get info in */ 946 1.2 ragge int callcount; /* number of times to call routine */ 947 1.1 ragge int scount; /* number of files/records to space */ 948 1.1 ragge int spaceop = 0; /* flag for skip/space operation */ 949 1.1 ragge int error = 0; 950 1.1 ragge 951 1.2 ragge #ifdef TSDEBUG 952 1.2 ragge printf("tsioctl (%x, %lx, %p, %d)\n", dev, cmd, data, flag); 953 1.2 ragge #endif 954 1.2 ragge 955 1.2 ragge bp = &sc->ts_cbuf; 956 1.1 ragge 957 1.1 ragge switch (cmd) { 958 1.1 ragge case MTIOCTOP: /* do a mag tape op */ 959 1.1 ragge mtop = (struct mtop *)data; 960 1.1 ragge switch (mtop->mt_op) { 961 1.1 ragge case MTWEOF: /* write an end-of-file record */ 962 1.1 ragge callcount = mtop->mt_count; 963 1.1 ragge scount = 1; 964 1.1 ragge break; 965 1.1 ragge case MTFSR: /* forward space record */ 966 1.1 ragge case MTBSR: /* backward space record */ 967 1.1 ragge spaceop = 1; 968 1.2 ragge case MTFSF: /* forward space file */ 969 1.2 ragge case MTBSF: /* backward space file */ 970 1.1 ragge callcount = 1; 971 1.1 ragge scount = mtop->mt_count; 972 1.1 ragge break; 973 1.1 ragge case MTREW: /* rewind */ 974 1.1 ragge case MTOFFL: /* rewind and put the drive offline */ 975 1.1 ragge case MTNOP: /* no operation, sets status only */ 976 1.1 ragge callcount = 1; 977 1.1 ragge scount = 1; /* wait for this rewind */ 978 1.1 ragge break; 979 1.1 ragge case MTRETEN: /* retension */ 980 1.1 ragge case MTERASE: /* erase entire tape */ 981 1.1 ragge case MTEOM: /* forward to end of media */ 982 1.1 ragge case MTNBSF: /* backward space to begin of file */ 983 1.1 ragge case MTCACHE: /* enable controller cache */ 984 1.1 ragge case MTNOCACHE: /* disable controller cache */ 985 1.1 ragge case MTSETBSIZ: /* set block size; 0 for variable */ 986 1.1 ragge case MTSETDNSTY: /* set density code for current mode */ 987 1.2 ragge printf("ioctl %d not implemented.\n", mtop->mt_op); 988 1.1 ragge return (ENXIO); 989 1.1 ragge default: 990 1.2 ragge #ifdef TSDEBUG 991 1.2 ragge printf("invalid ioctl %d\n", mtop->mt_op); 992 1.2 ragge #endif 993 1.1 ragge return (ENXIO); 994 1.1 ragge } /* switch (mtop->mt_op) */ 995 1.1 ragge 996 1.1 ragge if (callcount <= 0 || scount <= 0) { 997 1.2 ragge #ifdef TSDEBUG 998 1.2 ragge printf("invalid values %d/%d\n", callcount, scount); 999 1.2 ragge #endif 1000 1.1 ragge return (EINVAL); 1001 1.1 ragge } 1002 1.1 ragge do { 1003 1.2 ragge tscommand(sc, dev, mtop->mt_op, scount); 1004 1.1 ragge if (spaceop && bp->b_resid) { 1005 1.2 ragge #ifdef TSDEBUG 1006 1.2 ragge printf(("spaceop didn't complete\n")); 1007 1.2 ragge #endif 1008 1.1 ragge return (EIO); 1009 1.1 ragge } 1010 1.20 ad if (bp->b_error != 0) { 1011 1.2 ragge #ifdef TSDEBUG 1012 1.2 ragge printf("error in ioctl %d\n", mtop->mt_op); 1013 1.2 ragge #endif 1014 1.1 ragge break; 1015 1.1 ragge } 1016 1.1 ragge } while (--callcount > 0); 1017 1.20 ad if (bp->b_error != 0) 1018 1.20 ad error = bp->b_error; 1019 1.13 simonb return (error); 1020 1.1 ragge 1021 1.1 ragge case MTIOCGET: /* get tape status */ 1022 1.1 ragge mtget = (struct mtget *)data; 1023 1.1 ragge mtget->mt_type = MT_ISTS; 1024 1.2 ragge mtget->mt_dsreg = TS_RCSR(TSSR); 1025 1.2 ragge mtget->mt_erreg = sc->sc_vts->status.xst0; 1026 1.1 ragge mtget->mt_resid = 0; /* ??? */ 1027 1.1 ragge mtget->mt_density = 0; /* ??? */ 1028 1.1 ragge break; 1029 1.1 ragge 1030 1.1 ragge case MTIOCIEOT: /* ignore EOT error */ 1031 1.2 ragge #ifdef TSDEBUG 1032 1.2 ragge printf(("MTIOCIEOT not implemented.\n")); 1033 1.2 ragge #endif 1034 1.13 simonb return (ENXIO); 1035 1.1 ragge 1036 1.1 ragge case MTIOCEEOT: /* enable EOT error */ 1037 1.2 ragge #ifdef TSDEBUG 1038 1.2 ragge printf(("MTIOCEEOT not implemented.\n")); 1039 1.2 ragge #endif 1040 1.1 ragge return (ENXIO); 1041 1.1 ragge 1042 1.1 ragge default: 1043 1.2 ragge #ifdef TSDEBUG 1044 1.2 ragge printf("invalid ioctl cmd 0x%lx\n", cmd); 1045 1.2 ragge #endif 1046 1.1 ragge return (ENXIO); 1047 1.1 ragge } 1048 1.1 ragge 1049 1.1 ragge return (0); 1050 1.1 ragge } 1051 1.1 ragge 1052 1.1 ragge 1053 1.1 ragge /* 1054 1.13 simonb * 1055 1.1 ragge */ 1056 1.1 ragge int 1057 1.2 ragge tsread(dev_t dev, struct uio *uio, int flag) 1058 1.1 ragge { 1059 1.1 ragge return (physio (tsstrategy, NULL, dev, B_READ, minphys, uio)); 1060 1.1 ragge } 1061 1.1 ragge 1062 1.1 ragge /* 1063 1.1 ragge * 1064 1.1 ragge */ 1065 1.1 ragge int 1066 1.2 ragge tswrite(dev_t dev, struct uio *uio, int flag) 1067 1.1 ragge { 1068 1.1 ragge return (physio (tsstrategy, NULL, dev, B_WRITE, minphys, uio)); 1069 1.1 ragge } 1070 1.1 ragge 1071 1.1 ragge /* 1072 1.1 ragge * 1073 1.1 ragge */ 1074 1.1 ragge int 1075 1.24 matt tsdump(dev_t dev, daddr_t blkno, void *va, size_t size) 1076 1.1 ragge { 1077 1.2 ragge return EIO; 1078 1.1 ragge } 1079