1 1.68 thorpej /* $NetBSD: ed_mca.c,v 1.68 2022/09/25 17:21:18 thorpej Exp $ */ 2 1.1 jdolecek 3 1.1 jdolecek /* 4 1.1 jdolecek * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 1.41 martin * All rights reserved. 6 1.1 jdolecek * 7 1.1 jdolecek * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jdolecek * by Jaromir Dolecek. 9 1.1 jdolecek * 10 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 11 1.1 jdolecek * modification, are permitted provided that the following conditions 12 1.1 jdolecek * are met: 13 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 14 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 15 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 17 1.1 jdolecek * documentation and/or other materials provided with the distribution. 18 1.1 jdolecek * 19 1.41 martin * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.41 martin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.41 martin * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.41 martin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.41 martin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.41 martin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.41 martin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.41 martin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.41 martin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.41 martin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.41 martin * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jdolecek */ 31 1.1 jdolecek 32 1.1 jdolecek /* 33 1.10 jdolecek * Disk drive goo for MCA ESDI controller driver. 34 1.1 jdolecek */ 35 1.9 lukem 36 1.9 lukem #include <sys/cdefs.h> 37 1.68 thorpej __KERNEL_RCSID(0, "$NetBSD: ed_mca.c,v 1.68 2022/09/25 17:21:18 thorpej Exp $"); 38 1.1 jdolecek 39 1.1 jdolecek #include <sys/param.h> 40 1.1 jdolecek #include <sys/systm.h> 41 1.1 jdolecek #include <sys/kernel.h> 42 1.1 jdolecek #include <sys/conf.h> 43 1.1 jdolecek #include <sys/file.h> 44 1.1 jdolecek #include <sys/stat.h> 45 1.1 jdolecek #include <sys/ioctl.h> 46 1.1 jdolecek #include <sys/buf.h> 47 1.27 yamt #include <sys/bufq.h> 48 1.1 jdolecek #include <sys/uio.h> 49 1.1 jdolecek #include <sys/device.h> 50 1.1 jdolecek #include <sys/disklabel.h> 51 1.1 jdolecek #include <sys/disk.h> 52 1.1 jdolecek #include <sys/syslog.h> 53 1.1 jdolecek #include <sys/proc.h> 54 1.1 jdolecek #include <sys/vnode.h> 55 1.63 riastrad #include <sys/rndsource.h> 56 1.1 jdolecek 57 1.39 ad #include <sys/intr.h> 58 1.39 ad #include <sys/bus.h> 59 1.1 jdolecek 60 1.4 jdolecek #include <dev/mca/mcavar.h> 61 1.4 jdolecek 62 1.2 jdolecek #include <dev/mca/edcreg.h> 63 1.1 jdolecek #include <dev/mca/edvar.h> 64 1.2 jdolecek #include <dev/mca/edcvar.h> 65 1.1 jdolecek 66 1.23 thorpej /* #define ATADEBUG */ 67 1.1 jdolecek 68 1.23 thorpej #ifdef ATADEBUG 69 1.23 thorpej #define ATADEBUG_PRINT(args, level) printf args 70 1.1 jdolecek #else 71 1.23 thorpej #define ATADEBUG_PRINT(args, level) 72 1.1 jdolecek #endif 73 1.1 jdolecek 74 1.1 jdolecek #define EDLABELDEV(dev) (MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART)) 75 1.1 jdolecek 76 1.65 msaitoh static int ed_mca_probe (device_t, cfdata_t, void *); 77 1.65 msaitoh static void ed_mca_attach (device_t, device_t, void *); 78 1.1 jdolecek 79 1.53 chs CFATTACH_DECL_NEW(ed_mca, sizeof(struct ed_softc), 80 1.17 thorpej ed_mca_probe, ed_mca_attach, NULL, NULL); 81 1.1 jdolecek 82 1.1 jdolecek extern struct cfdriver ed_cd; 83 1.1 jdolecek 84 1.28 perry static int ed_get_params(struct ed_softc *, int *); 85 1.28 perry static void edgetdisklabel(dev_t, struct ed_softc *); 86 1.28 perry static void edgetdefaultlabel(struct ed_softc *, struct disklabel *); 87 1.14 gehenna 88 1.14 gehenna dev_type_open(edmcaopen); 89 1.14 gehenna dev_type_close(edmcaclose); 90 1.14 gehenna dev_type_read(edmcaread); 91 1.14 gehenna dev_type_write(edmcawrite); 92 1.14 gehenna dev_type_ioctl(edmcaioctl); 93 1.14 gehenna dev_type_strategy(edmcastrategy); 94 1.14 gehenna dev_type_dump(edmcadump); 95 1.14 gehenna dev_type_size(edmcasize); 96 1.14 gehenna 97 1.14 gehenna const struct bdevsw ed_bdevsw = { 98 1.54 dholland .d_open = edmcaopen, 99 1.54 dholland .d_close = edmcaclose, 100 1.54 dholland .d_strategy = edmcastrategy, 101 1.54 dholland .d_ioctl = edmcaioctl, 102 1.54 dholland .d_dump = edmcadump, 103 1.54 dholland .d_psize = edmcasize, 104 1.56 dholland .d_discard = nodiscard, 105 1.54 dholland .d_flag = D_DISK 106 1.14 gehenna }; 107 1.14 gehenna 108 1.14 gehenna const struct cdevsw ed_cdevsw = { 109 1.54 dholland .d_open = edmcaopen, 110 1.54 dholland .d_close = edmcaclose, 111 1.54 dholland .d_read = edmcaread, 112 1.54 dholland .d_write = edmcawrite, 113 1.54 dholland .d_ioctl = edmcaioctl, 114 1.54 dholland .d_stop = nostop, 115 1.54 dholland .d_tty = notty, 116 1.54 dholland .d_poll = nopoll, 117 1.54 dholland .d_mmap = nommap, 118 1.54 dholland .d_kqfilter = nokqfilter, 119 1.57 dholland .d_discard = nodiscard, 120 1.54 dholland .d_flag = D_DISK 121 1.14 gehenna }; 122 1.1 jdolecek 123 1.64 mlelstv static struct dkdriver eddkdriver = { 124 1.64 mlelstv .d_strategy = edmcastrategy, 125 1.64 mlelstv .d_minphys = minphys 126 1.64 mlelstv }; 127 1.1 jdolecek 128 1.1 jdolecek /* 129 1.1 jdolecek * Just check if it's possible to identify the disk. 130 1.1 jdolecek */ 131 1.1 jdolecek static int 132 1.53 chs ed_mca_probe(device_t parent, cfdata_t cf, void *aux) 133 1.1 jdolecek { 134 1.53 chs struct edc_mca_softc *sc = device_private(parent); 135 1.53 chs struct ed_attach_args *eda = aux; 136 1.1 jdolecek u_int16_t cmd_args[2]; 137 1.6 jdolecek int found = 1; 138 1.1 jdolecek 139 1.1 jdolecek /* 140 1.1 jdolecek * Get Device Configuration (09). 141 1.1 jdolecek */ 142 1.6 jdolecek cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */ 143 1.1 jdolecek cmd_args[1] = 0; 144 1.10 jdolecek if (edc_run_cmd(sc, CMD_GET_DEV_CONF, eda->edc_drive, cmd_args, 2, 1)) 145 1.6 jdolecek found = 0; 146 1.1 jdolecek 147 1.6 jdolecek return (found); 148 1.1 jdolecek } 149 1.1 jdolecek 150 1.1 jdolecek static void 151 1.47 cegger ed_mca_attach(device_t parent, device_t self, void *aux) 152 1.1 jdolecek { 153 1.32 thorpej struct ed_softc *ed = device_private(self); 154 1.32 thorpej struct edc_mca_softc *sc = device_private(parent); 155 1.53 chs struct ed_attach_args *eda = aux; 156 1.25 thorpej char pbuf[8]; 157 1.10 jdolecek int drv_flags; 158 1.1 jdolecek 159 1.53 chs ed->sc_dev = self; 160 1.2 jdolecek ed->edc_softc = sc; 161 1.10 jdolecek ed->sc_devno = eda->edc_drive; 162 1.10 jdolecek edc_add_disk(sc, ed); 163 1.1 jdolecek 164 1.30 yamt bufq_alloc(&ed->sc_q, "disksort", BUFQ_SORT_RAWBLOCK); 165 1.55 skrll mutex_init(&ed->sc_q_lock, MUTEX_DEFAULT, IPL_VM); 166 1.1 jdolecek 167 1.10 jdolecek if (ed_get_params(ed, &drv_flags)) { 168 1.66 msaitoh aprint_error(": IDENTIFY failed, no disk found\n"); 169 1.1 jdolecek return; 170 1.1 jdolecek } 171 1.1 jdolecek 172 1.1 jdolecek format_bytes(pbuf, sizeof(pbuf), 173 1.1 jdolecek (u_int64_t) ed->sc_capacity * DEV_BSIZE); 174 1.66 msaitoh aprint_normal(": %s, %u cyl, %u head, %u sec, 512 bytes/sect x " 175 1.66 msaitoh "%u sectors\n", pbuf, 176 1.66 msaitoh ed->cyl, ed->heads, ed->sectors, 177 1.66 msaitoh ed->sc_capacity); 178 1.66 msaitoh 179 1.66 msaitoh aprint_normal("%s: %u spares/cyl, %s, %s, %s, %s, %s\n", 180 1.66 msaitoh device_xname(ed->sc_dev), ed->spares, 181 1.66 msaitoh (drv_flags & (1 << 0)) ? "NoRetries" : "Retries", 182 1.66 msaitoh (drv_flags & (1 << 1)) ? "Removable" : "Fixed", 183 1.66 msaitoh (drv_flags & (1 << 2)) ? "SkewedFormat" : "NoSkew", 184 1.66 msaitoh (drv_flags & (1 << 3)) ? "ZeroDefect" : "Defects", 185 1.66 msaitoh (drv_flags & (1 << 4)) ? "InvalidSecondary" : "SecondaryOK"); 186 1.8 sommerfe 187 1.1 jdolecek /* 188 1.1 jdolecek * Initialize and attach the disk structure. 189 1.1 jdolecek */ 190 1.53 chs disk_init(&ed->sc_dk, device_xname(ed->sc_dev), &eddkdriver); 191 1.1 jdolecek disk_attach(&ed->sc_dk); 192 1.53 chs rnd_attach_source(&ed->rnd_source, device_xname(ed->sc_dev), 193 1.58 tls RND_TYPE_DISK, RND_FLAG_DEFAULT); 194 1.1 jdolecek 195 1.6 jdolecek ed->sc_flags |= EDF_INIT; 196 1.25 thorpej 197 1.26 thorpej /* 198 1.26 thorpej * XXX We should try to discovery wedges here, but 199 1.26 thorpej * XXX that would mean being able to do I/O. Should 200 1.26 thorpej * XXX use config_defer() here. 201 1.26 thorpej */ 202 1.1 jdolecek } 203 1.1 jdolecek 204 1.1 jdolecek /* 205 1.1 jdolecek * Read/write routine for a buffer. Validates the arguments and schedules the 206 1.1 jdolecek * transfer. Does not wait for the transfer to complete. 207 1.1 jdolecek */ 208 1.1 jdolecek void 209 1.44 dsl edmcastrategy(struct buf *bp) 210 1.1 jdolecek { 211 1.42 tsutsui struct ed_softc *ed; 212 1.42 tsutsui struct disklabel *lp; 213 1.1 jdolecek daddr_t blkno; 214 1.1 jdolecek 215 1.42 tsutsui ed = device_lookup_private(&ed_cd, DISKUNIT(bp->b_dev)); 216 1.42 tsutsui lp = ed->sc_dk.dk_label; 217 1.42 tsutsui 218 1.53 chs ATADEBUG_PRINT(("edmcastrategy (%s)\n", device_xname(ed->sc_dev)), 219 1.1 jdolecek DEBUG_XFERS); 220 1.8 sommerfe 221 1.1 jdolecek /* Valid request? */ 222 1.1 jdolecek if (bp->b_blkno < 0 || 223 1.1 jdolecek (bp->b_bcount % lp->d_secsize) != 0 || 224 1.1 jdolecek (bp->b_bcount / lp->d_secsize) >= (1 << NBBY)) { 225 1.1 jdolecek bp->b_error = EINVAL; 226 1.37 ad goto done; 227 1.1 jdolecek } 228 1.8 sommerfe 229 1.1 jdolecek /* If device invalidated (e.g. media change, door open), error. */ 230 1.10 jdolecek if ((ed->sc_flags & WDF_LOADED) == 0) { 231 1.1 jdolecek bp->b_error = EIO; 232 1.37 ad goto done; 233 1.1 jdolecek } 234 1.1 jdolecek 235 1.1 jdolecek /* If it's a null transfer, return immediately. */ 236 1.1 jdolecek if (bp->b_bcount == 0) 237 1.1 jdolecek goto done; 238 1.1 jdolecek 239 1.1 jdolecek /* 240 1.1 jdolecek * Do bounds checking, adjust transfer. if error, process. 241 1.1 jdolecek * If end of partition, just return. 242 1.1 jdolecek */ 243 1.1 jdolecek if (DISKPART(bp->b_dev) != RAW_PART && 244 1.20 thorpej bounds_check_with_label(&ed->sc_dk, bp, 245 1.10 jdolecek (ed->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0) 246 1.1 jdolecek goto done; 247 1.1 jdolecek 248 1.1 jdolecek /* 249 1.1 jdolecek * Now convert the block number to absolute and put it in 250 1.1 jdolecek * terms of the device's logical block size. 251 1.1 jdolecek */ 252 1.1 jdolecek if (lp->d_secsize >= DEV_BSIZE) 253 1.1 jdolecek blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); 254 1.1 jdolecek else 255 1.1 jdolecek blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize); 256 1.1 jdolecek 257 1.1 jdolecek if (DISKPART(bp->b_dev) != RAW_PART) 258 1.1 jdolecek blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 259 1.1 jdolecek 260 1.1 jdolecek bp->b_rawblkno = blkno; 261 1.1 jdolecek 262 1.1 jdolecek /* Queue transfer on drive, activate drive and controller if idle. */ 263 1.55 skrll mutex_enter(&ed->sc_q_lock); 264 1.43 yamt bufq_put(ed->sc_q, bp); 265 1.55 skrll mutex_exit(&ed->sc_q_lock); 266 1.1 jdolecek 267 1.1 jdolecek /* Ring the worker thread */ 268 1.48 rmind wakeup(ed->edc_softc); 269 1.1 jdolecek 270 1.1 jdolecek return; 271 1.1 jdolecek done: 272 1.1 jdolecek /* Toss transfer; we're done early. */ 273 1.1 jdolecek bp->b_resid = bp->b_bcount; 274 1.1 jdolecek biodone(bp); 275 1.1 jdolecek } 276 1.1 jdolecek 277 1.1 jdolecek int 278 1.34 christos edmcaread(dev_t dev, struct uio *uio, int flags) 279 1.1 jdolecek { 280 1.23 thorpej ATADEBUG_PRINT(("edread\n"), DEBUG_XFERS); 281 1.1 jdolecek return (physio(edmcastrategy, NULL, dev, B_READ, minphys, uio)); 282 1.1 jdolecek } 283 1.1 jdolecek 284 1.1 jdolecek int 285 1.34 christos edmcawrite(dev_t dev, struct uio *uio, int flags) 286 1.1 jdolecek { 287 1.23 thorpej ATADEBUG_PRINT(("edwrite\n"), DEBUG_XFERS); 288 1.1 jdolecek return (physio(edmcastrategy, NULL, dev, B_WRITE, minphys, uio)); 289 1.1 jdolecek } 290 1.1 jdolecek 291 1.1 jdolecek int 292 1.34 christos edmcaopen(dev_t dev, int flag, int fmt, struct lwp *l) 293 1.1 jdolecek { 294 1.1 jdolecek struct ed_softc *wd; 295 1.1 jdolecek int part, error; 296 1.1 jdolecek 297 1.23 thorpej ATADEBUG_PRINT(("edopen\n"), DEBUG_FUNCS); 298 1.42 tsutsui wd = device_lookup_private(&ed_cd, DISKUNIT(dev)); 299 1.6 jdolecek if (wd == NULL || (wd->sc_flags & EDF_INIT) == 0) 300 1.1 jdolecek return (ENXIO); 301 1.1 jdolecek 302 1.25 thorpej part = DISKPART(dev); 303 1.25 thorpej 304 1.36 ad mutex_enter(&wd->sc_dk.dk_openlock); 305 1.25 thorpej 306 1.25 thorpej /* 307 1.25 thorpej * If there are wedges, and this is not RAW_PART, then we 308 1.25 thorpej * need to fail. 309 1.25 thorpej */ 310 1.25 thorpej if (wd->sc_dk.dk_nwedges != 0 && part != RAW_PART) { 311 1.25 thorpej error = EBUSY; 312 1.25 thorpej goto bad1; 313 1.25 thorpej } 314 1.1 jdolecek 315 1.1 jdolecek if (wd->sc_dk.dk_openmask != 0) { 316 1.1 jdolecek /* 317 1.1 jdolecek * If any partition is open, but the disk has been invalidated, 318 1.1 jdolecek * disallow further opens. 319 1.1 jdolecek */ 320 1.1 jdolecek if ((wd->sc_flags & WDF_LOADED) == 0) { 321 1.1 jdolecek error = EIO; 322 1.25 thorpej goto bad1; 323 1.1 jdolecek } 324 1.1 jdolecek } else { 325 1.1 jdolecek if ((wd->sc_flags & WDF_LOADED) == 0) { 326 1.10 jdolecek int s; 327 1.10 jdolecek 328 1.1 jdolecek wd->sc_flags |= WDF_LOADED; 329 1.1 jdolecek 330 1.1 jdolecek /* Load the physical device parameters. */ 331 1.10 jdolecek s = splbio(); 332 1.10 jdolecek ed_get_params(wd, NULL); 333 1.10 jdolecek splx(s); 334 1.1 jdolecek 335 1.1 jdolecek /* Load the partition info if not already loaded. */ 336 1.10 jdolecek edgetdisklabel(dev, wd); 337 1.1 jdolecek } 338 1.1 jdolecek } 339 1.1 jdolecek 340 1.1 jdolecek /* Check that the partition exists. */ 341 1.1 jdolecek if (part != RAW_PART && 342 1.1 jdolecek (part >= wd->sc_dk.dk_label->d_npartitions || 343 1.1 jdolecek wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { 344 1.1 jdolecek error = ENXIO; 345 1.25 thorpej goto bad1; 346 1.1 jdolecek } 347 1.8 sommerfe 348 1.1 jdolecek /* Insure only one open at a time. */ 349 1.1 jdolecek switch (fmt) { 350 1.1 jdolecek case S_IFCHR: 351 1.1 jdolecek wd->sc_dk.dk_copenmask |= (1 << part); 352 1.1 jdolecek break; 353 1.1 jdolecek case S_IFBLK: 354 1.1 jdolecek wd->sc_dk.dk_bopenmask |= (1 << part); 355 1.1 jdolecek break; 356 1.1 jdolecek } 357 1.1 jdolecek wd->sc_dk.dk_openmask = 358 1.1 jdolecek wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 359 1.1 jdolecek 360 1.36 ad error = 0; 361 1.25 thorpej bad1: 362 1.36 ad mutex_exit(&wd->sc_dk.dk_openlock); 363 1.1 jdolecek return (error); 364 1.1 jdolecek } 365 1.1 jdolecek 366 1.1 jdolecek int 367 1.34 christos edmcaclose(dev_t dev, int flag, int fmt, struct lwp *l) 368 1.1 jdolecek { 369 1.42 tsutsui struct ed_softc *wd = device_lookup_private(&ed_cd, DISKUNIT(dev)); 370 1.1 jdolecek int part = DISKPART(dev); 371 1.8 sommerfe 372 1.23 thorpej ATADEBUG_PRINT(("edmcaclose\n"), DEBUG_FUNCS); 373 1.25 thorpej 374 1.36 ad mutex_enter(&wd->sc_dk.dk_openlock); 375 1.1 jdolecek 376 1.1 jdolecek switch (fmt) { 377 1.1 jdolecek case S_IFCHR: 378 1.1 jdolecek wd->sc_dk.dk_copenmask &= ~(1 << part); 379 1.1 jdolecek break; 380 1.1 jdolecek case S_IFBLK: 381 1.1 jdolecek wd->sc_dk.dk_bopenmask &= ~(1 << part); 382 1.1 jdolecek break; 383 1.1 jdolecek } 384 1.1 jdolecek wd->sc_dk.dk_openmask = 385 1.1 jdolecek wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 386 1.1 jdolecek 387 1.1 jdolecek if (wd->sc_dk.dk_openmask == 0) { 388 1.1 jdolecek #if 0 389 1.1 jdolecek wd_flushcache(wd, AT_WAIT); 390 1.1 jdolecek #endif 391 1.1 jdolecek /* XXXX Must wait for I/O to complete! */ 392 1.1 jdolecek 393 1.1 jdolecek if (! (wd->sc_flags & WDF_KLABEL)) 394 1.1 jdolecek wd->sc_flags &= ~WDF_LOADED; 395 1.1 jdolecek } 396 1.1 jdolecek 397 1.36 ad mutex_exit(&wd->sc_dk.dk_openlock); 398 1.1 jdolecek 399 1.1 jdolecek return 0; 400 1.1 jdolecek } 401 1.1 jdolecek 402 1.1 jdolecek static void 403 1.44 dsl edgetdefaultlabel(struct ed_softc *ed, struct disklabel *lp) 404 1.1 jdolecek { 405 1.23 thorpej ATADEBUG_PRINT(("edgetdefaultlabel\n"), DEBUG_FUNCS); 406 1.1 jdolecek memset(lp, 0, sizeof(struct disklabel)); 407 1.1 jdolecek 408 1.1 jdolecek lp->d_secsize = DEV_BSIZE; 409 1.10 jdolecek lp->d_ntracks = ed->heads; 410 1.10 jdolecek lp->d_nsectors = ed->sectors; 411 1.10 jdolecek lp->d_ncylinders = ed->cyl; 412 1.1 jdolecek lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 413 1.1 jdolecek 414 1.62 christos lp->d_type = DKTYPE_ESDI; 415 1.1 jdolecek 416 1.1 jdolecek strncpy(lp->d_typename, "ESDI", 16); 417 1.1 jdolecek strncpy(lp->d_packname, "fictitious", 16); 418 1.10 jdolecek lp->d_secperunit = ed->sc_capacity; 419 1.1 jdolecek lp->d_rpm = 3600; 420 1.1 jdolecek lp->d_interleave = 1; 421 1.1 jdolecek lp->d_flags = 0; 422 1.1 jdolecek 423 1.1 jdolecek lp->d_partitions[RAW_PART].p_offset = 0; 424 1.1 jdolecek lp->d_partitions[RAW_PART].p_size = 425 1.1 jdolecek lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 426 1.1 jdolecek lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 427 1.1 jdolecek lp->d_npartitions = RAW_PART + 1; 428 1.1 jdolecek 429 1.1 jdolecek lp->d_magic = DISKMAGIC; 430 1.1 jdolecek lp->d_magic2 = DISKMAGIC; 431 1.1 jdolecek lp->d_checksum = dkcksum(lp); 432 1.1 jdolecek } 433 1.1 jdolecek 434 1.1 jdolecek /* 435 1.1 jdolecek * Fabricate a default disk label, and try to read the correct one. 436 1.1 jdolecek */ 437 1.1 jdolecek static void 438 1.44 dsl edgetdisklabel(dev_t dev, struct ed_softc *ed) 439 1.1 jdolecek { 440 1.10 jdolecek struct disklabel *lp = ed->sc_dk.dk_label; 441 1.19 dsl const char *errstring; 442 1.1 jdolecek 443 1.23 thorpej ATADEBUG_PRINT(("edgetdisklabel\n"), DEBUG_FUNCS); 444 1.1 jdolecek 445 1.10 jdolecek memset(ed->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); 446 1.1 jdolecek 447 1.10 jdolecek edgetdefaultlabel(ed, lp); 448 1.1 jdolecek 449 1.10 jdolecek errstring = readdisklabel( 450 1.10 jdolecek EDLABELDEV(dev), edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 451 1.1 jdolecek if (errstring) { 452 1.1 jdolecek /* 453 1.1 jdolecek * This probably happened because the drive's default 454 1.1 jdolecek * geometry doesn't match the DOS geometry. We 455 1.1 jdolecek * assume the DOS geometry is now in the label and try 456 1.1 jdolecek * again. XXX This is a kluge. 457 1.1 jdolecek */ 458 1.1 jdolecek #if 0 459 1.1 jdolecek if (wd->drvp->state > RECAL) 460 1.52 bouyer wd->drvp->drive_flags |= ATA_DRIVE_RESET; 461 1.1 jdolecek #endif 462 1.10 jdolecek errstring = readdisklabel(EDLABELDEV(dev), 463 1.10 jdolecek edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 464 1.1 jdolecek } 465 1.1 jdolecek if (errstring) { 466 1.53 chs printf("%s: %s\n", device_xname(ed->sc_dev), errstring); 467 1.1 jdolecek return; 468 1.1 jdolecek } 469 1.1 jdolecek } 470 1.1 jdolecek 471 1.1 jdolecek int 472 1.44 dsl edmcaioctl(dev_t dev, u_long xfer, void *addr, int flag, struct lwp *l) 473 1.1 jdolecek { 474 1.42 tsutsui struct ed_softc *ed = device_lookup_private(&ed_cd, DISKUNIT(dev)); 475 1.1 jdolecek int error; 476 1.1 jdolecek 477 1.23 thorpej ATADEBUG_PRINT(("edioctl\n"), DEBUG_FUNCS); 478 1.1 jdolecek 479 1.10 jdolecek if ((ed->sc_flags & WDF_LOADED) == 0) 480 1.1 jdolecek return EIO; 481 1.1 jdolecek 482 1.61 christos error = disk_ioctl(&ed->sc_dk, dev, xfer, addr, flag, l); 483 1.60 christos if (error != EPASSTHROUGH) 484 1.60 christos return error; 485 1.60 christos 486 1.1 jdolecek switch (xfer) { 487 1.1 jdolecek case DIOCWDINFO: 488 1.1 jdolecek case DIOCSDINFO: 489 1.1 jdolecek { 490 1.1 jdolecek struct disklabel *lp; 491 1.1 jdolecek 492 1.1 jdolecek lp = (struct disklabel *)addr; 493 1.1 jdolecek 494 1.1 jdolecek if ((flag & FWRITE) == 0) 495 1.1 jdolecek return EBADF; 496 1.1 jdolecek 497 1.36 ad mutex_enter(&ed->sc_dk.dk_openlock); 498 1.10 jdolecek ed->sc_flags |= WDF_LABELLING; 499 1.1 jdolecek 500 1.10 jdolecek error = setdisklabel(ed->sc_dk.dk_label, 501 1.1 jdolecek lp, /*wd->sc_dk.dk_openmask : */0, 502 1.10 jdolecek ed->sc_dk.dk_cpulabel); 503 1.1 jdolecek if (error == 0) { 504 1.1 jdolecek #if 0 505 1.1 jdolecek if (wd->drvp->state > RECAL) 506 1.52 bouyer wd->drvp->drive_flags |= ATA_DRIVE_RESET; 507 1.1 jdolecek #endif 508 1.10 jdolecek if (xfer == DIOCWDINFO) 509 1.1 jdolecek error = writedisklabel(EDLABELDEV(dev), 510 1.10 jdolecek edmcastrategy, ed->sc_dk.dk_label, 511 1.10 jdolecek ed->sc_dk.dk_cpulabel); 512 1.1 jdolecek } 513 1.1 jdolecek 514 1.10 jdolecek ed->sc_flags &= ~WDF_LABELLING; 515 1.36 ad mutex_exit(&ed->sc_dk.dk_openlock); 516 1.10 jdolecek return (error); 517 1.1 jdolecek } 518 1.1 jdolecek 519 1.1 jdolecek case DIOCKLABEL: 520 1.1 jdolecek if (*(int *)addr) 521 1.10 jdolecek ed->sc_flags |= WDF_KLABEL; 522 1.1 jdolecek else 523 1.10 jdolecek ed->sc_flags &= ~WDF_KLABEL; 524 1.1 jdolecek return 0; 525 1.8 sommerfe 526 1.1 jdolecek case DIOCWLABEL: 527 1.1 jdolecek if ((flag & FWRITE) == 0) 528 1.1 jdolecek return EBADF; 529 1.1 jdolecek if (*(int *)addr) 530 1.10 jdolecek ed->sc_flags |= WDF_WLABEL; 531 1.1 jdolecek else 532 1.10 jdolecek ed->sc_flags &= ~WDF_WLABEL; 533 1.1 jdolecek return 0; 534 1.1 jdolecek 535 1.1 jdolecek case DIOCGDEFLABEL: 536 1.10 jdolecek edgetdefaultlabel(ed, (struct disklabel *)addr); 537 1.1 jdolecek return 0; 538 1.1 jdolecek 539 1.10 jdolecek #if 0 540 1.1 jdolecek case DIOCWFORMAT: 541 1.1 jdolecek if ((flag & FWRITE) == 0) 542 1.1 jdolecek return EBADF; 543 1.1 jdolecek { 544 1.1 jdolecek register struct format_op *fop; 545 1.1 jdolecek struct iovec aiov; 546 1.1 jdolecek struct uio auio; 547 1.8 sommerfe 548 1.1 jdolecek fop = (struct format_op *)addr; 549 1.1 jdolecek aiov.iov_base = fop->df_buf; 550 1.1 jdolecek aiov.iov_len = fop->df_count; 551 1.1 jdolecek auio.uio_iov = &aiov; 552 1.1 jdolecek auio.uio_iovcnt = 1; 553 1.1 jdolecek auio.uio_resid = fop->df_count; 554 1.1 jdolecek auio.uio_segflg = 0; 555 1.1 jdolecek auio.uio_offset = 556 1.1 jdolecek fop->df_startblk * wd->sc_dk.dk_label->d_secsize; 557 1.31 christos auio.uio_lwp = l; 558 1.1 jdolecek error = physio(wdformat, NULL, dev, B_WRITE, minphys, 559 1.1 jdolecek &auio); 560 1.1 jdolecek fop->df_count -= auio.uio_resid; 561 1.1 jdolecek fop->df_reg[0] = wdc->sc_status; 562 1.1 jdolecek fop->df_reg[1] = wdc->sc_error; 563 1.1 jdolecek return error; 564 1.1 jdolecek } 565 1.1 jdolecek #endif 566 1.1 jdolecek 567 1.1 jdolecek default: 568 1.1 jdolecek return ENOTTY; 569 1.1 jdolecek } 570 1.1 jdolecek 571 1.1 jdolecek #ifdef DIAGNOSTIC 572 1.3 jdolecek panic("edioctl: impossible"); 573 1.1 jdolecek #endif 574 1.1 jdolecek } 575 1.1 jdolecek 576 1.1 jdolecek int 577 1.44 dsl edmcasize(dev_t dev) 578 1.1 jdolecek { 579 1.1 jdolecek struct ed_softc *wd; 580 1.1 jdolecek int part, omask; 581 1.1 jdolecek int size; 582 1.1 jdolecek 583 1.23 thorpej ATADEBUG_PRINT(("edsize\n"), DEBUG_FUNCS); 584 1.1 jdolecek 585 1.42 tsutsui wd = device_lookup_private(&ed_cd, DISKUNIT(dev)); 586 1.1 jdolecek if (wd == NULL) 587 1.1 jdolecek return (-1); 588 1.1 jdolecek 589 1.1 jdolecek part = DISKPART(dev); 590 1.1 jdolecek omask = wd->sc_dk.dk_openmask & (1 << part); 591 1.1 jdolecek 592 1.1 jdolecek if (omask == 0 && edmcaopen(dev, 0, S_IFBLK, NULL) != 0) 593 1.1 jdolecek return (-1); 594 1.1 jdolecek if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) 595 1.1 jdolecek size = -1; 596 1.1 jdolecek else 597 1.1 jdolecek size = wd->sc_dk.dk_label->d_partitions[part].p_size * 598 1.1 jdolecek (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); 599 1.1 jdolecek if (omask == 0 && edmcaclose(dev, 0, S_IFBLK, NULL) != 0) 600 1.1 jdolecek return (-1); 601 1.1 jdolecek return (size); 602 1.1 jdolecek } 603 1.1 jdolecek 604 1.1 jdolecek /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */ 605 1.6 jdolecek static int eddoingadump = 0; 606 1.6 jdolecek static int eddumprecalibrated = 0; 607 1.6 jdolecek static int eddumpmulti = 1; 608 1.1 jdolecek 609 1.1 jdolecek /* 610 1.1 jdolecek * Dump core after a system crash. 611 1.1 jdolecek */ 612 1.1 jdolecek int 613 1.44 dsl edmcadump(dev_t dev, daddr_t blkno, void *va, size_t size) 614 1.1 jdolecek { 615 1.6 jdolecek struct ed_softc *ed; /* disk unit to do the I/O */ 616 1.1 jdolecek struct disklabel *lp; /* disk's disklabel */ 617 1.7 jdolecek int part; 618 1.1 jdolecek int nblks; /* total number of sectors left to write */ 619 1.10 jdolecek int error; 620 1.1 jdolecek 621 1.1 jdolecek /* Check if recursive dump; if so, punt. */ 622 1.6 jdolecek if (eddoingadump) 623 1.1 jdolecek return EFAULT; 624 1.6 jdolecek eddoingadump = 1; 625 1.1 jdolecek 626 1.42 tsutsui ed = device_lookup_private(&ed_cd, DISKUNIT(dev)); 627 1.6 jdolecek if (ed == NULL) 628 1.1 jdolecek return (ENXIO); 629 1.1 jdolecek 630 1.1 jdolecek part = DISKPART(dev); 631 1.1 jdolecek 632 1.1 jdolecek /* Make sure it was initialized. */ 633 1.6 jdolecek if ((ed->sc_flags & EDF_INIT) == 0) 634 1.1 jdolecek return ENXIO; 635 1.1 jdolecek 636 1.1 jdolecek /* Convert to disk sectors. Request must be a multiple of size. */ 637 1.6 jdolecek lp = ed->sc_dk.dk_label; 638 1.1 jdolecek if ((size % lp->d_secsize) != 0) 639 1.1 jdolecek return EFAULT; 640 1.1 jdolecek nblks = size / lp->d_secsize; 641 1.1 jdolecek blkno = blkno / (lp->d_secsize / DEV_BSIZE); 642 1.1 jdolecek 643 1.1 jdolecek /* Check transfer bounds against partition size. */ 644 1.1 jdolecek if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size)) 645 1.8 sommerfe return EINVAL; 646 1.1 jdolecek 647 1.1 jdolecek /* Offset block number to start of partition. */ 648 1.1 jdolecek blkno += lp->d_partitions[part].p_offset; 649 1.1 jdolecek 650 1.1 jdolecek /* Recalibrate, if first dump transfer. */ 651 1.6 jdolecek if (eddumprecalibrated == 0) { 652 1.6 jdolecek eddumprecalibrated = 1; 653 1.6 jdolecek eddumpmulti = 8; 654 1.1 jdolecek #if 0 655 1.1 jdolecek wd->drvp->state = RESET; 656 1.1 jdolecek #endif 657 1.1 jdolecek } 658 1.8 sommerfe 659 1.1 jdolecek while (nblks > 0) { 660 1.10 jdolecek error = edc_bio(ed->edc_softc, ed, va, blkno, 661 1.67 riastrad uimin(nblks, eddumpmulti) * lp->d_secsize, 0, 1); 662 1.10 jdolecek if (error) 663 1.10 jdolecek return (error); 664 1.1 jdolecek 665 1.1 jdolecek /* update block count */ 666 1.67 riastrad nblks -= uimin(nblks, eddumpmulti); 667 1.67 riastrad blkno += uimin(nblks, eddumpmulti); 668 1.67 riastrad va = (char *)va + uimin(nblks, eddumpmulti) * lp->d_secsize; 669 1.1 jdolecek } 670 1.1 jdolecek 671 1.6 jdolecek eddoingadump = 0; 672 1.6 jdolecek return (0); 673 1.1 jdolecek } 674 1.1 jdolecek 675 1.1 jdolecek static int 676 1.44 dsl ed_get_params(struct ed_softc *ed, int *drv_flags) 677 1.1 jdolecek { 678 1.1 jdolecek u_int16_t cmd_args[2]; 679 1.1 jdolecek 680 1.1 jdolecek /* 681 1.1 jdolecek * Get Device Configuration (09). 682 1.1 jdolecek */ 683 1.5 jdolecek cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */ 684 1.1 jdolecek cmd_args[1] = 0; 685 1.6 jdolecek if (edc_run_cmd(ed->edc_softc, CMD_GET_DEV_CONF, ed->sc_devno, 686 1.10 jdolecek cmd_args, 2, 1)) 687 1.1 jdolecek return (1); 688 1.1 jdolecek 689 1.10 jdolecek ed->spares = ed->sense_data[1] >> 8; 690 1.10 jdolecek if (drv_flags) 691 1.10 jdolecek *drv_flags = ed->sense_data[1] & 0x1f; 692 1.10 jdolecek ed->rba = ed->sense_data[2] | (ed->sense_data[3] << 16); 693 1.1 jdolecek /* Instead of using: 694 1.10 jdolecek ed->cyl = ed->sense_data[4]; 695 1.10 jdolecek ed->heads = ed->sense_data[5] & 0xff; 696 1.10 jdolecek ed->sectors = ed->sense_data[5] >> 8; 697 1.1 jdolecek * we fabricate the numbers from RBA count, so that 698 1.1 jdolecek * number of sectors is 32 and heads 64. This seems 699 1.1 jdolecek * to be necessary for integrated ESDI controller. 700 1.1 jdolecek */ 701 1.1 jdolecek ed->sectors = 32; 702 1.1 jdolecek ed->heads = 64; 703 1.1 jdolecek ed->cyl = ed->rba / (ed->heads * ed->sectors); 704 1.1 jdolecek ed->sc_capacity = ed->rba; 705 1.1 jdolecek 706 1.1 jdolecek return (0); 707 1.1 jdolecek } 708