1 1.53 thorpej /* $NetBSD: rl.c,v 1.53 2021/08/07 16:19:15 thorpej Exp $ */ 2 1.1 ragge 3 1.1 ragge /* 4 1.1 ragge * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved. 5 1.1 ragge * 6 1.1 ragge * Redistribution and use in source and binary forms, with or without 7 1.1 ragge * modification, are permitted provided that the following conditions 8 1.1 ragge * are met: 9 1.1 ragge * 1. Redistributions of source code must retain the above copyright 10 1.1 ragge * notice, this list of conditions and the following disclaimer. 11 1.1 ragge * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 ragge * notice, this list of conditions and the following disclaimer in the 13 1.1 ragge * documentation and/or other materials provided with the distribution. 14 1.1 ragge * 15 1.1 ragge * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 ragge * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.1 ragge * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.1 ragge * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.1 ragge * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 1.1 ragge * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 1.1 ragge * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 1.1 ragge * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 1.1 ragge * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 1.1 ragge * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 1.1 ragge */ 26 1.1 ragge 27 1.1 ragge /* 28 1.1 ragge * RL11/RLV11/RLV12 disk controller driver and 29 1.1 ragge * RL01/RL02 disk device driver. 30 1.1 ragge * 31 1.1 ragge * TODO: 32 1.1 ragge * Handle disk errors more gracefully 33 1.1 ragge * Do overlapping seeks on multiple drives 34 1.1 ragge * 35 1.1 ragge * Implementation comments: 36 1.24 simonb * 37 1.1 ragge */ 38 1.10 lukem 39 1.10 lukem #include <sys/cdefs.h> 40 1.53 thorpej __KERNEL_RCSID(0, "$NetBSD: rl.c,v 1.53 2021/08/07 16:19:15 thorpej Exp $"); 41 1.1 ragge 42 1.1 ragge #include <sys/param.h> 43 1.1 ragge #include <sys/device.h> 44 1.1 ragge #include <sys/systm.h> 45 1.1 ragge #include <sys/conf.h> 46 1.1 ragge #include <sys/disk.h> 47 1.1 ragge #include <sys/disklabel.h> 48 1.1 ragge #include <sys/buf.h> 49 1.23 yamt #include <sys/bufq.h> 50 1.1 ragge #include <sys/stat.h> 51 1.1 ragge #include <sys/dkio.h> 52 1.1 ragge #include <sys/fcntl.h> 53 1.17 jdolecek #include <sys/event.h> 54 1.1 ragge 55 1.1 ragge #include <ufs/ufs/dinode.h> 56 1.1 ragge #include <ufs/ffs/fs.h> 57 1.1 ragge 58 1.37 ad #include <sys/bus.h> 59 1.1 ragge 60 1.1 ragge #include <dev/qbus/ubavar.h> 61 1.1 ragge #include <dev/qbus/rlreg.h> 62 1.11 ragge #include <dev/qbus/rlvar.h> 63 1.1 ragge 64 1.1 ragge #include "ioconf.h" 65 1.1 ragge #include "locators.h" 66 1.1 ragge 67 1.38 matt static int rlcmatch(device_t, cfdata_t, void *); 68 1.38 matt static void rlcattach(device_t, device_t, void *); 69 1.1 ragge static int rlcprint(void *, const char *); 70 1.1 ragge static void rlcintr(void *); 71 1.38 matt static int rlmatch(device_t, cfdata_t, void *); 72 1.38 matt static void rlattach(device_t, device_t, void *); 73 1.1 ragge static void rlcstart(struct rlc_softc *, struct buf *); 74 1.1 ragge static void waitcrdy(struct rlc_softc *); 75 1.38 matt static void rlcreset(device_t); 76 1.1 ragge 77 1.38 matt CFATTACH_DECL_NEW(rlc, sizeof(struct rlc_softc), 78 1.16 thorpej rlcmatch, rlcattach, NULL, NULL); 79 1.15 thorpej 80 1.38 matt CFATTACH_DECL_NEW(rl, sizeof(struct rl_softc), 81 1.16 thorpej rlmatch, rlattach, NULL, NULL); 82 1.1 ragge 83 1.38 matt static dev_type_open(rlopen); 84 1.38 matt static dev_type_close(rlclose); 85 1.38 matt static dev_type_read(rlread); 86 1.38 matt static dev_type_write(rlwrite); 87 1.38 matt static dev_type_ioctl(rlioctl); 88 1.38 matt static dev_type_strategy(rlstrategy); 89 1.38 matt static dev_type_dump(rldump); 90 1.38 matt static dev_type_size(rlpsize); 91 1.13 gehenna 92 1.13 gehenna const struct bdevsw rl_bdevsw = { 93 1.43 dholland .d_open = rlopen, 94 1.43 dholland .d_close = rlclose, 95 1.43 dholland .d_strategy = rlstrategy, 96 1.43 dholland .d_ioctl = rlioctl, 97 1.43 dholland .d_dump = rldump, 98 1.43 dholland .d_psize = rlpsize, 99 1.44 dholland .d_discard = nodiscard, 100 1.43 dholland .d_flag = D_DISK 101 1.13 gehenna }; 102 1.13 gehenna 103 1.13 gehenna const struct cdevsw rl_cdevsw = { 104 1.43 dholland .d_open = rlopen, 105 1.43 dholland .d_close = rlclose, 106 1.43 dholland .d_read = rlread, 107 1.43 dholland .d_write = rlwrite, 108 1.43 dholland .d_ioctl = rlioctl, 109 1.43 dholland .d_stop = nostop, 110 1.43 dholland .d_tty = notty, 111 1.43 dholland .d_poll = nopoll, 112 1.43 dholland .d_mmap = nommap, 113 1.43 dholland .d_kqfilter = nokqfilter, 114 1.45 dholland .d_discard = nodiscard, 115 1.43 dholland .d_flag = D_DISK 116 1.13 gehenna }; 117 1.13 gehenna 118 1.1 ragge #define MAXRLXFER (RL_BPS * RL_SPT) 119 1.1 ragge 120 1.1 ragge #define RL_WREG(reg, val) \ 121 1.1 ragge bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val)) 122 1.1 ragge #define RL_RREG(reg) \ 123 1.1 ragge bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg)) 124 1.1 ragge 125 1.38 matt static const char * const rlstates[] = { 126 1.11 ragge "drive not loaded", 127 1.11 ragge "drive spinning up", 128 1.11 ragge "drive brushes out", 129 1.11 ragge "drive loading heads", 130 1.11 ragge "drive seeking", 131 1.11 ragge "drive ready", 132 1.11 ragge "drive unloading heads", 133 1.11 ragge "drive spun down", 134 1.11 ragge }; 135 1.11 ragge 136 1.38 matt static const struct dkdriver rldkdriver = { 137 1.50 mlelstv .d_strategy = rlstrategy, 138 1.50 mlelstv .d_minphys = minphys 139 1.22 thorpej }; 140 1.22 thorpej 141 1.25 ragge static const char * 142 1.11 ragge rlstate(struct rlc_softc *sc, int unit) 143 1.11 ragge { 144 1.11 ragge int i = 0; 145 1.11 ragge 146 1.11 ragge do { 147 1.11 ragge RL_WREG(RL_DA, RLDA_GS); 148 1.11 ragge RL_WREG(RL_CS, RLCS_GS|(unit << RLCS_USHFT)); 149 1.11 ragge waitcrdy(sc); 150 1.11 ragge } while (((RL_RREG(RL_CS) & RLCS_ERR) != 0) && i++ < 10); 151 1.11 ragge if (i == 10) 152 1.11 ragge return NULL; 153 1.11 ragge i = RL_RREG(RL_MP) & RLMP_STATUS; 154 1.11 ragge return rlstates[i]; 155 1.11 ragge } 156 1.11 ragge 157 1.1 ragge void 158 1.1 ragge waitcrdy(struct rlc_softc *sc) 159 1.1 ragge { 160 1.1 ragge int i; 161 1.1 ragge 162 1.1 ragge for (i = 0; i < 1000; i++) { 163 1.1 ragge DELAY(10000); 164 1.1 ragge if (RL_RREG(RL_CS) & RLCS_CRDY) 165 1.1 ragge return; 166 1.1 ragge } 167 1.38 matt aprint_error_dev(sc->sc_dev, "never got ready\n"); /* ?panic? */ 168 1.1 ragge } 169 1.1 ragge 170 1.1 ragge int 171 1.1 ragge rlcprint(void *aux, const char *name) 172 1.1 ragge { 173 1.1 ragge struct rlc_attach_args *ra = aux; 174 1.1 ragge 175 1.1 ragge if (name) 176 1.18 thorpej aprint_normal("RL0%d at %s", 177 1.18 thorpej ra->type & RLMP_DT ? '2' : '1', name); 178 1.18 thorpej aprint_normal(" drive %d", ra->hwid); 179 1.1 ragge return UNCONF; 180 1.1 ragge } 181 1.1 ragge 182 1.1 ragge /* 183 1.1 ragge * Force the controller to interrupt. 184 1.1 ragge */ 185 1.1 ragge int 186 1.38 matt rlcmatch(device_t parent, cfdata_t cf, void *aux) 187 1.1 ragge { 188 1.1 ragge struct uba_attach_args *ua = aux; 189 1.1 ragge struct rlc_softc ssc, *sc = &ssc; 190 1.1 ragge int i; 191 1.1 ragge 192 1.1 ragge sc->sc_iot = ua->ua_iot; 193 1.1 ragge sc->sc_ioh = ua->ua_ioh; 194 1.1 ragge /* Force interrupt by issuing a "Get Status" command */ 195 1.1 ragge RL_WREG(RL_DA, RLDA_GS); 196 1.1 ragge RL_WREG(RL_CS, RLCS_GS|RLCS_IE); 197 1.1 ragge 198 1.1 ragge for (i = 0; i < 100; i++) { 199 1.1 ragge DELAY(100000); 200 1.1 ragge if (RL_RREG(RL_CS) & RLCS_CRDY) 201 1.1 ragge return 1; 202 1.1 ragge } 203 1.1 ragge return 0; 204 1.1 ragge } 205 1.1 ragge 206 1.1 ragge void 207 1.38 matt rlcattach(device_t parent, device_t self, void *aux) 208 1.1 ragge { 209 1.30 thorpej struct rlc_softc *sc = device_private(self); 210 1.1 ragge struct uba_attach_args *ua = aux; 211 1.1 ragge struct rlc_attach_args ra; 212 1.1 ragge int i, error; 213 1.1 ragge 214 1.38 matt sc->sc_dev = self; 215 1.38 matt sc->sc_uh = device_private(parent); 216 1.1 ragge sc->sc_iot = ua->ua_iot; 217 1.1 ragge sc->sc_ioh = ua->ua_ioh; 218 1.1 ragge sc->sc_dmat = ua->ua_dmat; 219 1.4 matt uba_intr_establish(ua->ua_icookie, ua->ua_cvec, 220 1.4 matt rlcintr, sc, &sc->sc_intrcnt); 221 1.5 matt evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt, 222 1.38 matt device_xname(sc->sc_dev), "intr"); 223 1.11 ragge uba_reset_establish(rlcreset, self); 224 1.11 ragge 225 1.1 ragge printf("\n"); 226 1.1 ragge 227 1.1 ragge /* 228 1.24 simonb * The RL11 can only have one transfer going at a time, 229 1.1 ragge * and max transfer size is one track, so only one dmamap 230 1.1 ragge * is needed. 231 1.1 ragge */ 232 1.1 ragge error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0, 233 1.1 ragge BUS_DMA_ALLOCNOW, &sc->sc_dmam); 234 1.1 ragge if (error) { 235 1.38 matt aprint_error(": Failed to allocate DMA map, error %d\n", error); 236 1.1 ragge return; 237 1.1 ragge } 238 1.26 yamt bufq_alloc(&sc->sc_q, "disksort", BUFQ_SORT_CYLINDER); 239 1.1 ragge for (i = 0; i < RL_MAXDPC; i++) { 240 1.1 ragge waitcrdy(sc); 241 1.1 ragge RL_WREG(RL_DA, RLDA_GS|RLDA_RST); 242 1.1 ragge RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT)); 243 1.1 ragge waitcrdy(sc); 244 1.1 ragge ra.type = RL_RREG(RL_MP); 245 1.1 ragge ra.hwid = i; 246 1.1 ragge if ((RL_RREG(RL_CS) & RLCS_ERR) == 0) 247 1.53 thorpej config_found(sc->sc_dev, &ra, rlcprint, CFARGS_NONE); 248 1.1 ragge } 249 1.1 ragge } 250 1.1 ragge 251 1.1 ragge int 252 1.38 matt rlmatch(device_t parent, cfdata_t cf, void *aux) 253 1.1 ragge { 254 1.1 ragge struct rlc_attach_args *ra = aux; 255 1.1 ragge 256 1.1 ragge if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT && 257 1.1 ragge cf->cf_loc[RLCCF_DRIVE] != ra->hwid) 258 1.1 ragge return 0; 259 1.1 ragge return 1; 260 1.1 ragge } 261 1.1 ragge 262 1.1 ragge void 263 1.38 matt rlattach(device_t parent, device_t self, void *aux) 264 1.1 ragge { 265 1.30 thorpej struct rl_softc *rc = device_private(self); 266 1.1 ragge struct rlc_attach_args *ra = aux; 267 1.1 ragge struct disklabel *dl; 268 1.1 ragge 269 1.38 matt rc->rc_dev = self; 270 1.38 matt rc->rc_rlc = device_private(parent); 271 1.1 ragge rc->rc_hwid = ra->hwid; 272 1.38 matt disk_init(&rc->rc_disk, device_xname(rc->rc_dev), &rldkdriver); 273 1.1 ragge disk_attach(&rc->rc_disk); 274 1.1 ragge dl = rc->rc_disk.dk_label; 275 1.1 ragge dl->d_npartitions = 3; 276 1.1 ragge strcpy(dl->d_typename, "RL01"); 277 1.1 ragge if (ra->type & RLMP_DT) 278 1.1 ragge dl->d_typename[3] = '2'; 279 1.1 ragge dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */ 280 1.1 ragge dl->d_nsectors = RL_SPT/2; 281 1.1 ragge dl->d_ntracks = RL_SPD; 282 1.1 ragge dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01; 283 1.1 ragge dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; 284 1.1 ragge dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl; 285 1.1 ragge dl->d_partitions[0].p_size = dl->d_partitions[2].p_size = 286 1.1 ragge dl->d_secperunit; 287 1.1 ragge dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0; 288 1.1 ragge dl->d_interleave = dl->d_headswitch = 1; 289 1.1 ragge dl->d_bbsize = BBSIZE; 290 1.19 he dl->d_sbsize = SBLOCKSIZE; 291 1.1 ragge dl->d_rpm = 2400; 292 1.49 christos dl->d_type = DKTYPE_DEC; 293 1.38 matt printf(": %s, %s\n", dl->d_typename, rlstate(rc->rc_rlc, ra->hwid)); 294 1.22 thorpej 295 1.22 thorpej /* 296 1.22 thorpej * XXX We should try to discovery wedges here, but 297 1.22 thorpej * XXX that would mean loading up the pack and being 298 1.22 thorpej * XXX able to do I/O. Should use config_defer() here. 299 1.22 thorpej */ 300 1.1 ragge } 301 1.1 ragge 302 1.1 ragge int 303 1.27 christos rlopen(dev_t dev, int flag, int fmt, struct lwp *l) 304 1.1 ragge { 305 1.38 matt struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 306 1.38 matt struct rlc_softc *sc; 307 1.38 matt int error, part, mask; 308 1.1 ragge struct disklabel *dl; 309 1.20 dsl const char *msg; 310 1.11 ragge 311 1.1 ragge /* 312 1.1 ragge * Make sure this is a reasonable open request. 313 1.1 ragge */ 314 1.38 matt if (rc == NULL) 315 1.1 ragge return ENXIO; 316 1.1 ragge 317 1.38 matt sc = rc->rc_rlc; 318 1.22 thorpej part = DISKPART(dev); 319 1.22 thorpej 320 1.34 ad mutex_enter(&rc->rc_disk.dk_openlock); 321 1.22 thorpej 322 1.22 thorpej /* 323 1.22 thorpej * If there are wedges, and this is not RAW_PART, then we 324 1.22 thorpej * need to fail. 325 1.22 thorpej */ 326 1.22 thorpej if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) { 327 1.22 thorpej error = EBUSY; 328 1.22 thorpej goto bad1; 329 1.22 thorpej } 330 1.22 thorpej 331 1.11 ragge /* Check that the disk actually is useable */ 332 1.11 ragge msg = rlstate(sc, rc->rc_hwid); 333 1.11 ragge if (msg == NULL || msg == rlstates[RLMP_UNLOAD] || 334 1.22 thorpej msg == rlstates[RLMP_SPUNDOWN]) { 335 1.22 thorpej error = ENXIO; 336 1.22 thorpej goto bad1; 337 1.22 thorpej } 338 1.1 ragge /* 339 1.1 ragge * If this is the first open; read in where on the disk we are. 340 1.1 ragge */ 341 1.1 ragge dl = rc->rc_disk.dk_label; 342 1.1 ragge if (rc->rc_state == DK_CLOSED) { 343 1.1 ragge u_int16_t mp; 344 1.13 gehenna int maj; 345 1.1 ragge RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 346 1.1 ragge waitcrdy(sc); 347 1.1 ragge mp = RL_RREG(RL_MP); 348 1.1 ragge rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 349 1.1 ragge rc->rc_cyl = (mp >> 7) & 0777; 350 1.1 ragge rc->rc_state = DK_OPEN; 351 1.1 ragge /* Get disk label */ 352 1.13 gehenna maj = cdevsw_lookup_major(&rl_cdevsw); 353 1.13 gehenna if ((msg = readdisklabel(MAKEDISKDEV(maj, 354 1.38 matt device_unit(rc->rc_dev), RAW_PART), rlstrategy, dl, NULL))) 355 1.38 matt aprint_normal_dev(rc->rc_dev, "%s", msg); 356 1.38 matt aprint_normal_dev(rc->rc_dev, "size %d sectors\n", 357 1.38 matt dl->d_secperunit); 358 1.1 ragge } 359 1.22 thorpej if (part >= dl->d_npartitions) { 360 1.22 thorpej error = ENXIO; 361 1.22 thorpej goto bad1; 362 1.22 thorpej } 363 1.1 ragge 364 1.1 ragge mask = 1 << part; 365 1.1 ragge switch (fmt) { 366 1.1 ragge case S_IFCHR: 367 1.1 ragge rc->rc_disk.dk_copenmask |= mask; 368 1.1 ragge break; 369 1.1 ragge case S_IFBLK: 370 1.1 ragge rc->rc_disk.dk_bopenmask |= mask; 371 1.1 ragge break; 372 1.1 ragge } 373 1.1 ragge rc->rc_disk.dk_openmask |= mask; 374 1.34 ad error = 0; 375 1.22 thorpej bad1: 376 1.34 ad mutex_exit(&rc->rc_disk.dk_openlock); 377 1.22 thorpej return (error); 378 1.1 ragge } 379 1.1 ragge 380 1.1 ragge int 381 1.27 christos rlclose(dev_t dev, int flag, int fmt, struct lwp *l) 382 1.1 ragge { 383 1.34 ad int unit = DISKUNIT(dev); 384 1.39 drochner struct rl_softc *rc = device_lookup_private(&rl_cd, unit); 385 1.1 ragge int mask = (1 << DISKPART(dev)); 386 1.1 ragge 387 1.34 ad mutex_enter(&rc->rc_disk.dk_openlock); 388 1.22 thorpej 389 1.1 ragge switch (fmt) { 390 1.1 ragge case S_IFCHR: 391 1.1 ragge rc->rc_disk.dk_copenmask &= ~mask; 392 1.1 ragge break; 393 1.1 ragge case S_IFBLK: 394 1.1 ragge rc->rc_disk.dk_bopenmask &= ~mask; 395 1.1 ragge break; 396 1.1 ragge } 397 1.1 ragge rc->rc_disk.dk_openmask = 398 1.1 ragge rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask; 399 1.1 ragge 400 1.1 ragge if (rc->rc_disk.dk_openmask == 0) 401 1.1 ragge rc->rc_state = DK_CLOSED; /* May change pack */ 402 1.34 ad mutex_exit(&rc->rc_disk.dk_openlock); 403 1.1 ragge return 0; 404 1.1 ragge } 405 1.1 ragge 406 1.1 ragge void 407 1.1 ragge rlstrategy(struct buf *bp) 408 1.1 ragge { 409 1.38 matt struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev)); 410 1.1 ragge struct disklabel *lp; 411 1.38 matt int s; 412 1.38 matt 413 1.38 matt if (rc == NULL || rc->rc_state != DK_OPEN) /* How did we end up here at all? */ 414 1.1 ragge panic("rlstrategy: state impossible"); 415 1.1 ragge 416 1.1 ragge lp = rc->rc_disk.dk_label; 417 1.38 matt if (bounds_check_with_label(&rc->rc_disk, bp, 1) <= 0) 418 1.1 ragge goto done; 419 1.1 ragge 420 1.1 ragge if (bp->b_bcount == 0) 421 1.1 ragge goto done; 422 1.1 ragge 423 1.1 ragge bp->b_rawblkno = 424 1.1 ragge bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 425 1.1 ragge bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl; 426 1.1 ragge 427 1.8 thorpej s = splbio(); 428 1.40 yamt bufq_put(rc->rc_rlc->sc_q, bp); 429 1.38 matt rlcstart(rc->rc_rlc, 0); 430 1.1 ragge splx(s); 431 1.1 ragge return; 432 1.1 ragge 433 1.1 ragge done: biodone(bp); 434 1.1 ragge } 435 1.1 ragge 436 1.1 ragge int 437 1.31 christos rlioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 438 1.1 ragge { 439 1.39 drochner struct rl_softc *rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 440 1.1 ragge struct disklabel *lp = rc->rc_disk.dk_label; 441 1.47 christos int error; 442 1.6 fvdl #ifdef __HAVE_OLD_DISKLABEL 443 1.48 christos struct disklabel newlabel; 444 1.6 fvdl #endif 445 1.1 ragge 446 1.48 christos error = disk_ioctl(&rc->rc_disk, dev, cmd, addr, flag, l); 447 1.47 christos if (error != EPASSTHROUGH) 448 1.47 christos return error; 449 1.47 christos else 450 1.47 christos error = 0; 451 1.47 christos 452 1.1 ragge switch (cmd) { 453 1.1 ragge case DIOCSDINFO: 454 1.1 ragge case DIOCWDINFO: 455 1.6 fvdl #ifdef __HAVE_OLD_DISKLABEL 456 1.6 fvdl case ODIOCWDINFO: 457 1.6 fvdl case ODIOCSDINFO: 458 1.6 fvdl #endif 459 1.6 fvdl { 460 1.6 fvdl struct disklabel *tp; 461 1.6 fvdl 462 1.6 fvdl #ifdef __HAVE_OLD_DISKLABEL 463 1.6 fvdl if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 464 1.6 fvdl memset(&newlabel, 0, sizeof newlabel); 465 1.6 fvdl memcpy(&newlabel, addr, sizeof (struct olddisklabel)); 466 1.6 fvdl tp = &newlabel; 467 1.6 fvdl } else 468 1.6 fvdl #endif 469 1.6 fvdl tp = (struct disklabel *)addr; 470 1.6 fvdl 471 1.1 ragge if ((flag & FWRITE) == 0) 472 1.47 christos error = EBADF; 473 1.22 thorpej else { 474 1.34 ad mutex_enter(&rc->rc_disk.dk_openlock); 475 1.47 christos error = (( 476 1.6 fvdl #ifdef __HAVE_OLD_DISKLABEL 477 1.6 fvdl cmd == ODIOCSDINFO || 478 1.6 fvdl #endif 479 1.6 fvdl cmd == DIOCSDINFO) ? 480 1.6 fvdl setdisklabel(lp, tp, 0, 0) : 481 1.1 ragge writedisklabel(dev, rlstrategy, lp, 0)); 482 1.34 ad mutex_exit(&rc->rc_disk.dk_openlock); 483 1.22 thorpej } 484 1.1 ragge break; 485 1.6 fvdl } 486 1.1 ragge 487 1.1 ragge case DIOCWLABEL: 488 1.1 ragge if ((flag & FWRITE) == 0) 489 1.47 christos error = EBADF; 490 1.1 ragge break; 491 1.1 ragge 492 1.1 ragge default: 493 1.47 christos error = ENOTTY; 494 1.38 matt break; 495 1.1 ragge } 496 1.47 christos return error; 497 1.1 ragge } 498 1.1 ragge 499 1.1 ragge int 500 1.38 matt rlpsize(dev_t dev) 501 1.1 ragge { 502 1.38 matt struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 503 1.1 ragge struct disklabel *dl; 504 1.38 matt int size; 505 1.1 ragge 506 1.38 matt if (rc == NULL) 507 1.1 ragge return -1; 508 1.1 ragge dl = rc->rc_disk.dk_label; 509 1.1 ragge size = dl->d_partitions[DISKPART(dev)].p_size * 510 1.1 ragge (dl->d_secsize / DEV_BSIZE); 511 1.1 ragge return size; 512 1.1 ragge } 513 1.1 ragge 514 1.1 ragge int 515 1.31 christos rldump(dev_t dev, daddr_t blkno, void *va, size_t size) 516 1.1 ragge { 517 1.1 ragge /* Not likely... */ 518 1.1 ragge return 0; 519 1.1 ragge } 520 1.1 ragge 521 1.1 ragge int 522 1.1 ragge rlread(dev_t dev, struct uio *uio, int ioflag) 523 1.1 ragge { 524 1.1 ragge return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio)); 525 1.1 ragge } 526 1.1 ragge 527 1.1 ragge int 528 1.1 ragge rlwrite(dev_t dev, struct uio *uio, int ioflag) 529 1.1 ragge { 530 1.1 ragge return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio)); 531 1.1 ragge } 532 1.1 ragge 533 1.38 matt static const char * const rlerr[] = { 534 1.1 ragge "no", 535 1.1 ragge "operation incomplete", 536 1.1 ragge "read data CRC", 537 1.1 ragge "header CRC", 538 1.1 ragge "data late", 539 1.1 ragge "header not found", 540 1.1 ragge "", 541 1.1 ragge "", 542 1.9 wiz "non-existent memory", 543 1.1 ragge "memory parity error", 544 1.1 ragge "", 545 1.1 ragge "", 546 1.1 ragge "", 547 1.1 ragge "", 548 1.1 ragge "", 549 1.1 ragge "", 550 1.1 ragge }; 551 1.1 ragge 552 1.1 ragge void 553 1.1 ragge rlcintr(void *arg) 554 1.1 ragge { 555 1.1 ragge struct rlc_softc *sc = arg; 556 1.1 ragge struct buf *bp; 557 1.1 ragge u_int16_t cs; 558 1.1 ragge 559 1.1 ragge bp = sc->sc_active; 560 1.1 ragge if (bp == 0) { 561 1.38 matt aprint_error_dev(sc->sc_dev, "strange interrupt\n"); 562 1.1 ragge return; 563 1.1 ragge } 564 1.1 ragge bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam); 565 1.1 ragge sc->sc_active = 0; 566 1.1 ragge cs = RL_RREG(RL_CS); 567 1.1 ragge if (cs & RLCS_ERR) { 568 1.1 ragge int error = (cs & RLCS_ERRMSK) >> 10; 569 1.1 ragge 570 1.38 matt aprint_error_dev(sc->sc_dev, "%s\n", rlerr[error]); 571 1.1 ragge bp->b_error = EIO; 572 1.1 ragge bp->b_resid = bp->b_bcount; 573 1.1 ragge sc->sc_bytecnt = 0; 574 1.1 ragge } 575 1.1 ragge if (sc->sc_bytecnt == 0) /* Finished transfer */ 576 1.1 ragge biodone(bp); 577 1.1 ragge rlcstart(sc, sc->sc_bytecnt ? bp : 0); 578 1.1 ragge } 579 1.1 ragge 580 1.1 ragge /* 581 1.24 simonb * Start routine. First position the disk to the given position, 582 1.1 ragge * then start reading/writing. An optimization would be to be able 583 1.1 ragge * to handle overlapping seeks between disks. 584 1.1 ragge */ 585 1.1 ragge void 586 1.1 ragge rlcstart(struct rlc_softc *sc, struct buf *ob) 587 1.1 ragge { 588 1.1 ragge struct disklabel *lp; 589 1.1 ragge struct rl_softc *rc; 590 1.1 ragge struct buf *bp; 591 1.1 ragge int bn, cn, sn, tn, blks, err; 592 1.1 ragge 593 1.1 ragge if (sc->sc_active) 594 1.1 ragge return; /* Already doing something */ 595 1.1 ragge 596 1.1 ragge if (ob == 0) { 597 1.40 yamt bp = bufq_get(sc->sc_q); 598 1.1 ragge if (bp == NULL) 599 1.1 ragge return; /* Nothing to do */ 600 1.3 thorpej sc->sc_bufaddr = bp->b_data; 601 1.1 ragge sc->sc_diskblk = bp->b_rawblkno; 602 1.1 ragge sc->sc_bytecnt = bp->b_bcount; 603 1.1 ragge bp->b_resid = 0; 604 1.1 ragge } else 605 1.1 ragge bp = ob; 606 1.1 ragge sc->sc_active = bp; 607 1.1 ragge 608 1.39 drochner rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev)); 609 1.1 ragge bn = sc->sc_diskblk; 610 1.1 ragge lp = rc->rc_disk.dk_label; 611 1.1 ragge if (bn) { 612 1.1 ragge cn = bn / lp->d_secpercyl; 613 1.1 ragge sn = bn % lp->d_secpercyl; 614 1.1 ragge tn = sn / lp->d_nsectors; 615 1.1 ragge sn = sn % lp->d_nsectors; 616 1.1 ragge } else 617 1.1 ragge cn = sn = tn = 0; 618 1.1 ragge 619 1.1 ragge /* 620 1.1 ragge * Check if we have to position disk first. 621 1.1 ragge */ 622 1.1 ragge if (rc->rc_cyl != cn || rc->rc_head != tn) { 623 1.1 ragge u_int16_t da = RLDA_SEEK; 624 1.1 ragge if (cn > rc->rc_cyl) 625 1.1 ragge da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR; 626 1.1 ragge else 627 1.1 ragge da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT); 628 1.1 ragge if (tn) 629 1.1 ragge da |= RLDA_HSSEEK; 630 1.1 ragge waitcrdy(sc); 631 1.1 ragge RL_WREG(RL_DA, da); 632 1.1 ragge RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT)); 633 1.1 ragge waitcrdy(sc); 634 1.1 ragge rc->rc_cyl = cn; 635 1.1 ragge rc->rc_head = tn; 636 1.1 ragge } 637 1.1 ragge RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1)); 638 1.1 ragge blks = sc->sc_bytecnt/DEV_BSIZE; 639 1.1 ragge 640 1.1 ragge if (sn + blks > RL_SPT/2) 641 1.1 ragge blks = RL_SPT/2 - sn; 642 1.1 ragge RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2); 643 1.1 ragge err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr, 644 1.11 ragge (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0), 645 1.11 ragge BUS_DMA_NOWAIT); 646 1.1 ragge if (err) 647 1.1 ragge panic("%s: bus_dmamap_load failed: %d", 648 1.38 matt device_xname(sc->sc_dev), err); 649 1.1 ragge RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff)); 650 1.1 ragge 651 1.1 ragge /* Count up vars */ 652 1.33 christos sc->sc_bufaddr = (char *)sc->sc_bufaddr + (blks*DEV_BSIZE); 653 1.1 ragge sc->sc_diskblk += blks; 654 1.1 ragge sc->sc_bytecnt -= (blks*DEV_BSIZE); 655 1.1 ragge 656 1.1 ragge if (bp->b_flags & B_READ) 657 1.1 ragge RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT)); 658 1.1 ragge else 659 1.1 ragge RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT)); 660 1.2 ragge } 661 1.2 ragge 662 1.11 ragge /* 663 1.11 ragge * Called once per controller when an ubareset occurs. 664 1.11 ragge * Retracts all disks and restarts active transfers. 665 1.11 ragge */ 666 1.2 ragge void 667 1.38 matt rlcreset(device_t dev) 668 1.2 ragge { 669 1.38 matt struct rlc_softc *sc = device_private(dev); 670 1.11 ragge struct rl_softc *rc; 671 1.11 ragge int i; 672 1.2 ragge u_int16_t mp; 673 1.2 ragge 674 1.11 ragge for (i = 0; i < rl_cd.cd_ndevs; i++) { 675 1.38 matt if ((rc = device_lookup_private(&rl_cd, i)) == NULL) 676 1.11 ragge continue; 677 1.11 ragge if (rc->rc_state != DK_OPEN) 678 1.11 ragge continue; 679 1.38 matt if (rc->rc_rlc != sc) 680 1.38 matt continue; 681 1.11 ragge 682 1.11 ragge RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 683 1.11 ragge waitcrdy(sc); 684 1.11 ragge mp = RL_RREG(RL_MP); 685 1.11 ragge rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 686 1.11 ragge rc->rc_cyl = (mp >> 7) & 0777; 687 1.11 ragge } 688 1.2 ragge if (sc->sc_active == 0) 689 1.2 ragge return; 690 1.2 ragge 691 1.40 yamt bufq_put(sc->sc_q, sc->sc_active); 692 1.2 ragge sc->sc_active = 0; 693 1.2 ragge rlcstart(sc, 0); 694 1.1 ragge } 695