1 1.84 tsutsui /* $NetBSD: xy.c,v 1.84 2024/12/21 17:40:11 tsutsui Exp $ */ 2 1.1 gwr 3 1.1 gwr /* 4 1.1 gwr * Copyright (c) 1995 Charles D. Cranor 5 1.1 gwr * All rights reserved. 6 1.1 gwr * 7 1.1 gwr * Redistribution and use in source and binary forms, with or without 8 1.1 gwr * modification, are permitted provided that the following conditions 9 1.1 gwr * are met: 10 1.1 gwr * 1. Redistributions of source code must retain the above copyright 11 1.1 gwr * notice, this list of conditions and the following disclaimer. 12 1.1 gwr * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 gwr * notice, this list of conditions and the following disclaimer in the 14 1.1 gwr * documentation and/or other materials provided with the distribution. 15 1.1 gwr * 16 1.1 gwr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 gwr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 gwr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 gwr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 gwr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.1 gwr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 gwr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.1 gwr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.1 gwr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.1 gwr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 gwr */ 27 1.1 gwr 28 1.1 gwr /* 29 1.1 gwr * 30 1.1 gwr * x y . c x y l o g i c s 4 5 0 / 4 5 1 s m d d r i v e r 31 1.1 gwr * 32 1.72 chuck * author: Chuck Cranor <chuck@netbsd> 33 1.19 gwr * id: &Id: xy.c,v 1.1 1995/09/25 20:35:14 chuck Exp & 34 1.1 gwr * started: 14-Sep-95 35 1.1 gwr * references: [1] Xylogics Model 753 User's Manual 36 1.1 gwr * part number: 166-753-001, Revision B, May 21, 1988. 37 1.1 gwr * "Your Partner For Performance" 38 1.1 gwr * [2] other NetBSD disk device drivers 39 1.1 gwr * [3] Xylogics Model 450 User's Manual 40 1.1 gwr * part number: 166-017-001, Revision B, 1983. 41 1.17 gwr * [4] Addendum to Xylogics Model 450 Disk Controller User's 42 1.1 gwr * Manual, Jan. 1985. 43 1.1 gwr * [5] The 451 Controller, Rev. B3, September 2, 1986. 44 1.1 gwr * [6] David Jones <dej (at) achilles.net>'s unfinished 450/451 driver 45 1.1 gwr * 46 1.1 gwr */ 47 1.47 lukem 48 1.47 lukem #include <sys/cdefs.h> 49 1.84 tsutsui __KERNEL_RCSID(0, "$NetBSD: xy.c,v 1.84 2024/12/21 17:40:11 tsutsui Exp $"); 50 1.1 gwr 51 1.1 gwr #undef XYC_DEBUG /* full debug */ 52 1.1 gwr #undef XYC_DIAG /* extra sanity checks */ 53 1.1 gwr #if defined(DIAGNOSTIC) && !defined(XYC_DIAG) 54 1.1 gwr #define XYC_DIAG /* link in with master DIAG option */ 55 1.1 gwr #endif 56 1.1 gwr 57 1.1 gwr #include <sys/param.h> 58 1.1 gwr #include <sys/proc.h> 59 1.1 gwr #include <sys/systm.h> 60 1.1 gwr #include <sys/kernel.h> 61 1.1 gwr #include <sys/file.h> 62 1.1 gwr #include <sys/stat.h> 63 1.1 gwr #include <sys/ioctl.h> 64 1.1 gwr #include <sys/buf.h> 65 1.49 yamt #include <sys/bufq.h> 66 1.1 gwr #include <sys/uio.h> 67 1.80 thorpej #include <sys/kmem.h> 68 1.1 gwr #include <sys/device.h> 69 1.1 gwr #include <sys/disklabel.h> 70 1.1 gwr #include <sys/disk.h> 71 1.1 gwr #include <sys/syslog.h> 72 1.1 gwr #include <sys/dkbad.h> 73 1.13 gwr #include <sys/conf.h> 74 1.56 elad #include <sys/kauth.h> 75 1.13 gwr 76 1.33 mrg #include <uvm/uvm_extern.h> 77 1.1 gwr 78 1.21 mrg #include <dev/sun/disklabel.h> 79 1.21 mrg 80 1.1 gwr #include <machine/autoconf.h> 81 1.1 gwr #include <machine/dvma.h> 82 1.1 gwr 83 1.1 gwr #include <sun3/dev/xyreg.h> 84 1.1 gwr #include <sun3/dev/xyvar.h> 85 1.1 gwr #include <sun3/dev/xio.h> 86 1.1 gwr 87 1.69 tsutsui #include "ioconf.h" 88 1.17 gwr #include "locators.h" 89 1.22 gwr 90 1.22 gwr /* 91 1.22 gwr * Print a complaint when no xy children were specified 92 1.22 gwr * in the config file. Better than a link error... 93 1.22 gwr * 94 1.22 gwr * XXX: Some folks say this driver should be split in two, 95 1.22 gwr * but that seems pointless with ONLY one type of child. 96 1.22 gwr */ 97 1.22 gwr #include "xy.h" 98 1.22 gwr #if NXY == 0 99 1.22 gwr #error "xyc but no xy?" 100 1.22 gwr #endif 101 1.17 gwr 102 1.1 gwr /* 103 1.1 gwr * macros 104 1.1 gwr */ 105 1.1 gwr 106 1.1 gwr /* 107 1.1 gwr * XYC_GO: start iopb ADDR (DVMA addr in a u_long) on XYC 108 1.1 gwr */ 109 1.69 tsutsui #define XYC_GO(XYC, ADDR) \ 110 1.69 tsutsui do { \ 111 1.69 tsutsui (XYC)->xyc_addr_lo = ((ADDR) & 0xff); \ 112 1.69 tsutsui (ADDR) = ((ADDR) >> 8); \ 113 1.69 tsutsui (XYC)->xyc_addr_hi = ((ADDR) & 0xff); \ 114 1.69 tsutsui (ADDR) = ((ADDR) >> 8); \ 115 1.69 tsutsui (XYC)->xyc_reloc_lo = ((ADDR) & 0xff); \ 116 1.69 tsutsui (ADDR) = ((ADDR) >> 8); \ 117 1.69 tsutsui (XYC)->xyc_reloc_hi = (ADDR); \ 118 1.69 tsutsui (XYC)->xyc_csr = XYC_GBSY; /* go! */ \ 119 1.69 tsutsui } while (/* CONSTCOND */ 0) 120 1.1 gwr 121 1.1 gwr /* 122 1.1 gwr * XYC_DONE: don't need IORQ, get error code and free (done after xyc_cmd) 123 1.1 gwr */ 124 1.1 gwr 125 1.69 tsutsui #define XYC_DONE(SC,ER) \ 126 1.69 tsutsui do { \ 127 1.69 tsutsui if ((ER) == XY_ERR_AOK) { \ 128 1.69 tsutsui (ER) = (SC)->ciorq->errno; \ 129 1.69 tsutsui (SC)->ciorq->mode = XY_SUB_FREE; \ 130 1.69 tsutsui wakeup((SC)->ciorq); \ 131 1.69 tsutsui } \ 132 1.69 tsutsui } while (/* CONSTCOND */ 0) 133 1.1 gwr 134 1.1 gwr /* 135 1.1 gwr * XYC_ADVANCE: advance iorq's pointers by a number of sectors 136 1.1 gwr */ 137 1.1 gwr 138 1.69 tsutsui #define XYC_ADVANCE(IORQ, N) \ 139 1.69 tsutsui do { \ 140 1.69 tsutsui if (N) { \ 141 1.69 tsutsui (IORQ)->sectcnt -= (N); \ 142 1.69 tsutsui (IORQ)->blockno += (N); \ 143 1.69 tsutsui (IORQ)->dbuf += ((N) * XYFM_BPS); \ 144 1.69 tsutsui } \ 145 1.69 tsutsui } while (/* CONSTCOND */ 0) 146 1.1 gwr 147 1.1 gwr /* 148 1.1 gwr * note - addresses you can sleep on: 149 1.1 gwr * [1] & of xy_softc's "state" (waiting for a chance to attach a drive) 150 1.1 gwr * [2] & an iorq (waiting for an XY_SUB_WAIT iorq to finish) 151 1.1 gwr */ 152 1.1 gwr 153 1.1 gwr 154 1.1 gwr /* 155 1.1 gwr * function prototypes 156 1.1 gwr * "xyc_*" functions are internal, all others are external interfaces 157 1.1 gwr */ 158 1.1 gwr 159 1.1 gwr /* internals */ 160 1.50 chs struct xy_iopb *xyc_chain(struct xyc_softc *, struct xy_iorq *); 161 1.50 chs int xyc_cmd(struct xyc_softc *, int, int, int, int, int, char *, int); 162 1.51 tsutsui const char *xyc_e2str(int); 163 1.50 chs int xyc_entoact(int); 164 1.50 chs int xyc_error(struct xyc_softc *, struct xy_iorq *, struct xy_iopb *, int); 165 1.50 chs int xyc_ioctlcmd(struct xy_softc *, dev_t dev, struct xd_iocmd *); 166 1.50 chs void xyc_perror(struct xy_iorq *, struct xy_iopb *, int); 167 1.50 chs int xyc_piodriver(struct xyc_softc *, struct xy_iorq *); 168 1.50 chs int xyc_remove_iorq(struct xyc_softc *); 169 1.50 chs int xyc_reset(struct xyc_softc *, int, struct xy_iorq *, int, 170 1.50 chs struct xy_softc *); 171 1.50 chs inline void xyc_rqinit(struct xy_iorq *, struct xyc_softc *, struct xy_softc *, 172 1.59 christos int, u_long, int, void *, struct buf *); 173 1.50 chs void xyc_rqtopb(struct xy_iorq *, struct xy_iopb *, int, int); 174 1.50 chs void xyc_start(struct xyc_softc *, struct xy_iorq *); 175 1.50 chs int xyc_startbuf(struct xyc_softc *, struct xy_softc *, struct buf *); 176 1.50 chs int xyc_submit_iorq(struct xyc_softc *, struct xy_iorq *, int); 177 1.50 chs void xyc_tick(void *); 178 1.50 chs int xyc_unbusy(struct xyc *, int); 179 1.50 chs void xyc_xyreset(struct xyc_softc *, struct xy_softc *); 180 1.1 gwr 181 1.1 gwr /* machine interrupt hook */ 182 1.50 chs int xycintr(void *); 183 1.1 gwr 184 1.1 gwr /* autoconf */ 185 1.69 tsutsui static int xycmatch(device_t, cfdata_t, void *); 186 1.69 tsutsui static void xycattach(device_t, device_t, void *); 187 1.50 chs static int xyc_print(void *, const char *); 188 1.50 chs 189 1.69 tsutsui static int xymatch(device_t, cfdata_t, void *); 190 1.69 tsutsui static void xyattach(device_t, device_t, void *); 191 1.50 chs static void xy_init(struct xy_softc *); 192 1.1 gwr 193 1.50 chs static void xydummystrat(struct buf *); 194 1.50 chs int xygetdisklabel(struct xy_softc *, void *); 195 1.1 gwr 196 1.1 gwr /* 197 1.18 thorpej * cfattach's: device driver interface to autoconfig 198 1.1 gwr */ 199 1.1 gwr 200 1.69 tsutsui CFATTACH_DECL_NEW(xyc, sizeof(struct xyc_softc), 201 1.41 thorpej xycmatch, xycattach, NULL, NULL); 202 1.40 thorpej 203 1.69 tsutsui CFATTACH_DECL_NEW(xy, sizeof(struct xy_softc), 204 1.41 thorpej xymatch, xyattach, NULL, NULL); 205 1.9 thorpej 206 1.1 gwr struct xyc_attach_args { /* this is the "aux" args to xyattach */ 207 1.1 gwr int driveno; /* unit number */ 208 1.37 gehenna }; 209 1.37 gehenna 210 1.84 tsutsui static dev_type_open(xyopen); 211 1.84 tsutsui static dev_type_close(xyclose); 212 1.84 tsutsui static dev_type_read(xyread); 213 1.84 tsutsui static dev_type_write(xywrite); 214 1.84 tsutsui static dev_type_ioctl(xyioctl); 215 1.84 tsutsui static dev_type_strategy(xystrategy); 216 1.84 tsutsui static dev_type_dump(xydump); 217 1.84 tsutsui static dev_type_size(xysize); 218 1.37 gehenna 219 1.37 gehenna const struct bdevsw xy_bdevsw = { 220 1.74 dholland .d_open = xyopen, 221 1.74 dholland .d_close = xyclose, 222 1.74 dholland .d_strategy = xystrategy, 223 1.74 dholland .d_ioctl = xyioctl, 224 1.74 dholland .d_dump = xydump, 225 1.74 dholland .d_psize = xysize, 226 1.75 dholland .d_discard = nodiscard, 227 1.74 dholland .d_flag = D_DISK 228 1.37 gehenna }; 229 1.37 gehenna 230 1.37 gehenna const struct cdevsw xy_cdevsw = { 231 1.74 dholland .d_open = xyopen, 232 1.74 dholland .d_close = xyclose, 233 1.74 dholland .d_read = xyread, 234 1.74 dholland .d_write = xywrite, 235 1.74 dholland .d_ioctl = xyioctl, 236 1.74 dholland .d_stop = nostop, 237 1.74 dholland .d_tty = notty, 238 1.74 dholland .d_poll = nopoll, 239 1.74 dholland .d_mmap = nommap, 240 1.74 dholland .d_kqfilter = nokqfilter, 241 1.76 dholland .d_discard = nodiscard, 242 1.74 dholland .d_flag = D_DISK 243 1.1 gwr }; 244 1.1 gwr 245 1.1 gwr /* 246 1.1 gwr * dkdriver 247 1.1 gwr */ 248 1.1 gwr 249 1.78 mlelstv struct dkdriver xydkdriver = { 250 1.78 mlelstv .d_strategy = xystrategy 251 1.78 mlelstv }; 252 1.1 gwr 253 1.1 gwr /* 254 1.1 gwr * start: disk label fix code (XXX) 255 1.1 gwr */ 256 1.1 gwr 257 1.1 gwr static void *xy_labeldata; 258 1.1 gwr 259 1.83 tsutsui static void 260 1.50 chs xydummystrat(struct buf *bp) 261 1.1 gwr { 262 1.69 tsutsui 263 1.1 gwr if (bp->b_bcount != XYFM_BPS) 264 1.69 tsutsui panic("%s: b_bcount", __func__); 265 1.35 tsutsui memcpy(bp->b_data, xy_labeldata, XYFM_BPS); 266 1.64 ad bp->b_oflags |= BO_DONE; 267 1.64 ad bp->b_cflags &= ~BC_BUSY; 268 1.1 gwr } 269 1.1 gwr 270 1.83 tsutsui int 271 1.50 chs xygetdisklabel(struct xy_softc *xy, void *b) 272 1.1 gwr { 273 1.45 dsl const char *err; 274 1.1 gwr struct sun_disklabel *sdl; 275 1.1 gwr 276 1.1 gwr /* We already have the label data in `b'; setup for dummy strategy */ 277 1.1 gwr xy_labeldata = b; 278 1.1 gwr 279 1.1 gwr /* Required parameter for readdisklabel() */ 280 1.2 thorpej xy->sc_dk.dk_label->d_secsize = XYFM_BPS; 281 1.1 gwr 282 1.69 tsutsui err = readdisklabel(MAKEDISKDEV(0, device_unit(xy->sc_dev), RAW_PART), 283 1.69 tsutsui xydummystrat, xy->sc_dk.dk_label, xy->sc_dk.dk_cpulabel); 284 1.1 gwr if (err) { 285 1.69 tsutsui printf("%s: %s\n", device_xname(xy->sc_dev), err); 286 1.69 tsutsui return XY_ERR_FAIL; 287 1.1 gwr } 288 1.1 gwr 289 1.1 gwr /* Ok, we have the label; fill in `pcyl' if there's SunOS magic */ 290 1.2 thorpej sdl = (struct sun_disklabel *)xy->sc_dk.dk_cpulabel->cd_block; 291 1.1 gwr if (sdl->sl_magic == SUN_DKMAGIC) 292 1.1 gwr xy->pcyl = sdl->sl_pcyl; 293 1.1 gwr else { 294 1.17 gwr printf("%s: WARNING: no `pcyl' in disk label.\n", 295 1.69 tsutsui device_xname(xy->sc_dev)); 296 1.2 thorpej xy->pcyl = xy->sc_dk.dk_label->d_ncylinders + 297 1.69 tsutsui xy->sc_dk.dk_label->d_acylinders; 298 1.17 gwr printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n", 299 1.69 tsutsui device_xname(xy->sc_dev), xy->pcyl); 300 1.1 gwr } 301 1.1 gwr 302 1.2 thorpej xy->ncyl = xy->sc_dk.dk_label->d_ncylinders; 303 1.2 thorpej xy->acyl = xy->sc_dk.dk_label->d_acylinders; 304 1.2 thorpej xy->nhead = xy->sc_dk.dk_label->d_ntracks; 305 1.2 thorpej xy->nsect = xy->sc_dk.dk_label->d_nsectors; 306 1.1 gwr xy->sectpercyl = xy->nhead * xy->nsect; 307 1.69 tsutsui xy->sc_dk.dk_label->d_secsize = XYFM_BPS; /* not handled by 308 1.69 tsutsui * sun->bsd */ 309 1.69 tsutsui return XY_ERR_AOK; 310 1.1 gwr } 311 1.1 gwr 312 1.1 gwr /* 313 1.1 gwr * end: disk label fix code (XXX) 314 1.1 gwr */ 315 1.1 gwr 316 1.1 gwr /* 317 1.1 gwr * a u t o c o n f i g f u n c t i o n s 318 1.1 gwr */ 319 1.1 gwr 320 1.1 gwr /* 321 1.1 gwr * xycmatch: determine if xyc is present or not. we do a 322 1.1 gwr * soft reset to detect the xyc. 323 1.1 gwr */ 324 1.83 tsutsui static int 325 1.69 tsutsui xycmatch(device_t parent, cfdata_t cf, void *aux) 326 1.1 gwr { 327 1.1 gwr struct confargs *ca = aux; 328 1.1 gwr 329 1.17 gwr /* No default VME address. */ 330 1.17 gwr if (ca->ca_paddr == -1) 331 1.69 tsutsui return 0; 332 1.1 gwr 333 1.17 gwr /* Make sure something is there... */ 334 1.17 gwr if (bus_peek(ca->ca_bustype, ca->ca_paddr + 5, 1) == -1) 335 1.69 tsutsui return 0; 336 1.17 gwr 337 1.17 gwr /* Default interrupt priority. */ 338 1.1 gwr if (ca->ca_intpri == -1) 339 1.1 gwr ca->ca_intpri = 2; 340 1.1 gwr 341 1.69 tsutsui return 1; 342 1.1 gwr } 343 1.1 gwr 344 1.1 gwr /* 345 1.1 gwr * xycattach: attach controller 346 1.1 gwr */ 347 1.83 tsutsui static void 348 1.69 tsutsui xycattach(device_t parent, device_t self, void *aux) 349 1.1 gwr { 350 1.69 tsutsui struct xyc_softc *xyc = device_private(self); 351 1.1 gwr struct confargs *ca = aux; 352 1.1 gwr struct xyc_attach_args xa; 353 1.69 tsutsui int lcv, err, res, pbsz; 354 1.69 tsutsui void *tmp, *tmp2; 355 1.69 tsutsui u_long ultmp; 356 1.1 gwr 357 1.1 gwr /* get addressing and intr level stuff from autoconfig and load it 358 1.1 gwr * into our xyc_softc. */ 359 1.1 gwr 360 1.69 tsutsui xyc->sc_dev = self; 361 1.69 tsutsui xyc->xyc = (struct xyc *)bus_mapin(ca->ca_bustype, ca->ca_paddr, 362 1.69 tsutsui sizeof(struct xyc)); 363 1.19 gwr xyc->bustype = ca->ca_bustype; 364 1.19 gwr xyc->ipl = ca->ca_intpri; 365 1.19 gwr xyc->vector = ca->ca_intvec; 366 1.1 gwr xyc->no_ols = 0; /* XXX should be from config */ 367 1.1 gwr 368 1.1 gwr for (lcv = 0; lcv < XYC_MAXDEV; lcv++) 369 1.69 tsutsui xyc->sc_drives[lcv] = NULL; 370 1.1 gwr 371 1.17 gwr /* 372 1.1 gwr * allocate and zero buffers 373 1.17 gwr * check boundaries of the KVA's ... all IOPBs must reside in 374 1.17 gwr * the same 64K region. 375 1.1 gwr */ 376 1.1 gwr 377 1.1 gwr pbsz = XYC_MAXIOPB * sizeof(struct xy_iopb); 378 1.69 tsutsui tmp = tmp2 = (struct xy_iopb *)dvma_malloc(pbsz); /* KVA */ 379 1.69 tsutsui ultmp = (u_long)tmp; 380 1.1 gwr if ((ultmp & 0xffff0000) != ((ultmp + pbsz) & 0xffff0000)) { 381 1.69 tsutsui tmp = (struct xy_iopb *)dvma_malloc(pbsz); /* retry! */ 382 1.1 gwr dvma_free(tmp2, pbsz); 383 1.1 gwr ultmp = (u_long) tmp; 384 1.1 gwr if ((ultmp & 0xffff0000) != ((ultmp + pbsz) & 0xffff0000)) { 385 1.69 tsutsui aprint_error(": can't alloc IOPB mem in 64K\n"); 386 1.1 gwr return; 387 1.1 gwr } 388 1.1 gwr } 389 1.35 tsutsui memset(tmp, 0, pbsz); 390 1.1 gwr xyc->iopbase = tmp; 391 1.69 tsutsui xyc->dvmaiopb = 392 1.69 tsutsui (struct xy_iopb *)dvma_kvtopa(xyc->iopbase, xyc->bustype); 393 1.80 thorpej xyc->reqs = kmem_zalloc(XYC_MAXIOPB * sizeof(struct xy_iorq), 394 1.80 thorpej KM_SLEEP); 395 1.1 gwr 396 1.17 gwr /* 397 1.1 gwr * init iorq to iopb pointers, and non-zero fields in the 398 1.17 gwr * iopb which never change. 399 1.1 gwr */ 400 1.1 gwr 401 1.1 gwr for (lcv = 0; lcv < XYC_MAXIOPB; lcv++) { 402 1.1 gwr xyc->xy_chain[lcv] = NULL; 403 1.1 gwr xyc->reqs[lcv].iopb = &xyc->iopbase[lcv]; 404 1.1 gwr xyc->iopbase[lcv].asr = 1; /* always the same */ 405 1.1 gwr xyc->iopbase[lcv].eef = 1; /* always the same */ 406 1.1 gwr xyc->iopbase[lcv].ecm = XY_ECM; /* always the same */ 407 1.1 gwr xyc->iopbase[lcv].aud = 1; /* always the same */ 408 1.1 gwr xyc->iopbase[lcv].relo = 1; /* always the same */ 409 1.1 gwr xyc->iopbase[lcv].thro = XY_THRO;/* always the same */ 410 1.1 gwr } 411 1.1 gwr xyc->ciorq = &xyc->reqs[XYC_CTLIOPB]; /* short hand name */ 412 1.1 gwr xyc->ciopb = &xyc->iopbase[XYC_CTLIOPB]; /* short hand name */ 413 1.1 gwr xyc->xy_hand = 0; 414 1.1 gwr 415 1.1 gwr /* read controller parameters and insure we have a 450/451 */ 416 1.1 gwr 417 1.1 gwr err = xyc_cmd(xyc, XYCMD_ST, 0, 0, 0, 0, 0, XY_SUB_POLL); 418 1.1 gwr res = xyc->ciopb->ctyp; 419 1.1 gwr XYC_DONE(xyc, err); 420 1.1 gwr if (res != XYCT_450) { 421 1.1 gwr if (err) 422 1.69 tsutsui aprint_error(": %s: ", xyc_e2str(err)); 423 1.69 tsutsui aprint_error(": doesn't identify as a 450/451\n"); 424 1.1 gwr return; 425 1.1 gwr } 426 1.69 tsutsui aprint_normal(": Xylogics 450/451"); 427 1.1 gwr if (xyc->no_ols) 428 1.69 tsutsui /* 450 doesn't overlap seek right */ 429 1.69 tsutsui aprint_normal(" [OLS disabled]"); 430 1.69 tsutsui aprint_normal("\n"); 431 1.1 gwr if (err) { 432 1.69 tsutsui aprint_error_dev(self, "error: %s\n", xyc_e2str(err)); 433 1.1 gwr return; 434 1.1 gwr } 435 1.1 gwr if ((xyc->xyc->xyc_csr & XYC_ADRM) == 0) { 436 1.69 tsutsui aprint_error_dev(self, "24 bit addressing turned off\n"); 437 1.11 christos printf("please set hardware jumpers JM1-JM2=in, JM3-JM4=out\n"); 438 1.11 christos printf("to enable 24 bit mode and this driver\n"); 439 1.1 gwr return; 440 1.1 gwr } 441 1.1 gwr 442 1.1 gwr /* link in interrupt with higher level software */ 443 1.69 tsutsui isr_add_vectored(xycintr, xyc, ca->ca_intpri, ca->ca_intvec); 444 1.31 cgd evcnt_attach_dynamic(&xyc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 445 1.69 tsutsui device_xname(self), "intr"); 446 1.1 gwr 447 1.60 ad callout_init(&xyc->sc_tick_ch, 0); 448 1.26 thorpej 449 1.1 gwr /* now we must look for disks using autoconfig */ 450 1.1 gwr for (xa.driveno = 0; xa.driveno < XYC_MAXDEV; xa.driveno++) 451 1.82 thorpej (void)config_found(self, (void *)&xa, xyc_print, CFARGS_NONE); 452 1.1 gwr 453 1.1 gwr /* start the watchdog clock */ 454 1.26 thorpej callout_reset(&xyc->sc_tick_ch, XYC_TICKCNT, xyc_tick, xyc); 455 1.13 gwr } 456 1.13 gwr 457 1.83 tsutsui static int 458 1.50 chs xyc_print(void *aux, const char *name) 459 1.13 gwr { 460 1.13 gwr struct xyc_attach_args *xa = aux; 461 1.13 gwr 462 1.13 gwr if (name != NULL) 463 1.44 thorpej aprint_normal("%s: ", name); 464 1.13 gwr 465 1.13 gwr if (xa->driveno != -1) 466 1.44 thorpej aprint_normal(" drive %d", xa->driveno); 467 1.13 gwr 468 1.13 gwr return UNCONF; 469 1.1 gwr } 470 1.1 gwr 471 1.1 gwr /* 472 1.1 gwr * xymatch: probe for disk. 473 1.1 gwr * 474 1.1 gwr * note: we almost always say disk is present. this allows us to 475 1.1 gwr * spin up and configure a disk after the system is booted (we can 476 1.17 gwr * call xyattach!). Also, wire down the relationship between the 477 1.17 gwr * xy* and xyc* devices, to simplify boot device identification. 478 1.1 gwr */ 479 1.83 tsutsui static int 480 1.69 tsutsui xymatch(device_t parent, cfdata_t cf, void *aux) 481 1.1 gwr { 482 1.1 gwr struct xyc_attach_args *xa = aux; 483 1.17 gwr int xy_unit; 484 1.1 gwr 485 1.17 gwr /* Match only on the "wired-down" controller+disk. */ 486 1.55 tsutsui xy_unit = device_unit(parent) * 2 + xa->driveno; 487 1.17 gwr if (cf->cf_unit != xy_unit) 488 1.69 tsutsui return 0; 489 1.1 gwr 490 1.69 tsutsui return 1; 491 1.1 gwr } 492 1.1 gwr 493 1.1 gwr /* 494 1.17 gwr * xyattach: attach a disk. 495 1.1 gwr */ 496 1.83 tsutsui static void 497 1.69 tsutsui xyattach(device_t parent, device_t self, void *aux) 498 1.1 gwr { 499 1.69 tsutsui struct xy_softc *xy = device_private(self); 500 1.69 tsutsui struct xyc_softc *xyc = device_private(parent); 501 1.1 gwr struct xyc_attach_args *xa = aux; 502 1.17 gwr 503 1.69 tsutsui xy->sc_dev = self; 504 1.69 tsutsui aprint_normal("\n"); 505 1.1 gwr 506 1.2 thorpej /* 507 1.2 thorpej * Always re-initialize the disk structure. We want statistics 508 1.2 thorpej * to start with a clean slate. 509 1.2 thorpej */ 510 1.35 tsutsui memset(&xy->sc_dk, 0, sizeof(xy->sc_dk)); 511 1.69 tsutsui disk_init(&xy->sc_dk, device_xname(self), &xydkdriver); 512 1.2 thorpej 513 1.17 gwr xy->state = XY_DRIVE_UNKNOWN; /* to start */ 514 1.17 gwr xy->flags = 0; 515 1.17 gwr xy->parent = xyc; 516 1.17 gwr 517 1.17 gwr /* init queue of waiting bufs */ 518 1.52 yamt bufq_alloc(&xy->xyq, "disksort", BUFQ_SORT_RAWBLOCK); 519 1.17 gwr xy->xyrq = &xyc->reqs[xa->driveno]; 520 1.1 gwr 521 1.1 gwr xy->xy_drive = xa->driveno; 522 1.1 gwr xyc->sc_drives[xa->driveno] = xy; 523 1.1 gwr 524 1.17 gwr /* Do init work common to attach and open. */ 525 1.17 gwr xy_init(xy); 526 1.17 gwr } 527 1.17 gwr 528 1.17 gwr /* 529 1.17 gwr * end of autoconfig functions 530 1.17 gwr */ 531 1.1 gwr 532 1.17 gwr /* 533 1.17 gwr * Initialize a disk. This can be called from both autoconf and 534 1.17 gwr * also from xyopen/xystrategy. 535 1.17 gwr */ 536 1.83 tsutsui static void 537 1.50 chs xy_init(struct xy_softc *xy) 538 1.17 gwr { 539 1.17 gwr struct xyc_softc *xyc; 540 1.17 gwr struct dkbad *dkb; 541 1.17 gwr void *dvmabuf; 542 1.17 gwr int err, spt, mb, blk, lcv, fullmode, newstate; 543 1.1 gwr 544 1.17 gwr xyc = xy->parent; 545 1.1 gwr xy->state = XY_DRIVE_ATTACHING; 546 1.1 gwr newstate = XY_DRIVE_UNKNOWN; 547 1.17 gwr fullmode = (cold) ? XY_SUB_POLL : XY_SUB_WAIT; 548 1.17 gwr dvmabuf = dvma_malloc(XYFM_BPS); 549 1.1 gwr 550 1.1 gwr /* first try and reset the drive */ 551 1.1 gwr 552 1.17 gwr err = xyc_cmd(xyc, XYCMD_RST, 0, xy->xy_drive, 0, 0, 0, fullmode); 553 1.1 gwr XYC_DONE(xyc, err); 554 1.1 gwr if (err == XY_ERR_DNRY) { 555 1.17 gwr printf("%s: drive %d: off-line\n", 556 1.69 tsutsui device_xname(xy->sc_dev), xy->xy_drive); 557 1.1 gwr goto done; 558 1.1 gwr } 559 1.1 gwr if (err) { 560 1.17 gwr printf("%s: ERROR 0x%02x (%s)\n", 561 1.69 tsutsui device_xname(xy->sc_dev), err, xyc_e2str(err)); 562 1.1 gwr goto done; 563 1.1 gwr } 564 1.17 gwr printf("%s: drive %d ready", 565 1.69 tsutsui device_xname(xy->sc_dev), xy->xy_drive); 566 1.1 gwr 567 1.1 gwr /* 568 1.1 gwr * now set drive parameters (to semi-bogus values) so we can read the 569 1.1 gwr * disk label. 570 1.1 gwr */ 571 1.1 gwr xy->pcyl = xy->ncyl = 1; 572 1.1 gwr xy->acyl = 0; 573 1.1 gwr xy->nhead = 1; 574 1.1 gwr xy->nsect = 1; 575 1.1 gwr xy->sectpercyl = 1; 576 1.1 gwr for (lcv = 0; lcv < 126; lcv++) /* init empty bad144 table */ 577 1.17 gwr xy->dkb.bt_bad[lcv].bt_cyl = 578 1.69 tsutsui xy->dkb.bt_bad[lcv].bt_trksec = 0xffff; 579 1.1 gwr 580 1.1 gwr /* read disk label */ 581 1.69 tsutsui for (xy->drive_type = 0; xy->drive_type <= XYC_MAXDT; 582 1.69 tsutsui xy->drive_type++) { 583 1.17 gwr err = xyc_cmd(xyc, XYCMD_RD, 0, xy->xy_drive, 0, 1, 584 1.69 tsutsui dvmabuf, fullmode); 585 1.1 gwr XYC_DONE(xyc, err); 586 1.69 tsutsui if (err == XY_ERR_AOK) 587 1.69 tsutsui break; 588 1.1 gwr } 589 1.1 gwr 590 1.1 gwr if (err != XY_ERR_AOK) { 591 1.17 gwr printf("%s: reading disk label failed: %s\n", 592 1.69 tsutsui device_xname(xy->sc_dev), xyc_e2str(err)); 593 1.1 gwr goto done; 594 1.1 gwr } 595 1.17 gwr printf("%s: drive type %d\n", 596 1.69 tsutsui device_xname(xy->sc_dev), xy->drive_type); 597 1.1 gwr 598 1.1 gwr newstate = XY_DRIVE_NOLABEL; 599 1.1 gwr 600 1.1 gwr xy->hw_spt = spt = 0; /* XXX needed ? */ 601 1.3 chuck /* Attach the disk: must be before getdisklabel to malloc label */ 602 1.3 chuck disk_attach(&xy->sc_dk); 603 1.3 chuck 604 1.17 gwr if (xygetdisklabel(xy, dvmabuf) != XY_ERR_AOK) 605 1.1 gwr goto done; 606 1.1 gwr 607 1.1 gwr /* inform the user of what is up */ 608 1.17 gwr printf("%s: <%s>, pcyl %d\n", 609 1.69 tsutsui device_xname(xy->sc_dev), 610 1.69 tsutsui (char *)dvmabuf, xy->pcyl); 611 1.1 gwr mb = xy->ncyl * (xy->nhead * xy->nsect) / (1048576 / XYFM_BPS); 612 1.17 gwr printf("%s: %dMB, %d cyl, %d head, %d sec\n", 613 1.69 tsutsui device_xname(xy->sc_dev), mb, xy->ncyl, xy->nhead, xy->nsect); 614 1.1 gwr 615 1.1 gwr /* 616 1.1 gwr * 450/451 stupidity: the drive type is encoded into the format 617 1.1 gwr * of the disk. the drive type in the IOPB must match the drive 618 1.1 gwr * type in the format, or you will not be able to do I/O to the 619 1.17 gwr * disk (you get header not found errors). if you have two drives 620 1.17 gwr * of different sizes that have the same drive type in their 621 1.17 gwr * formatting then you are out of luck. 622 1.1 gwr * 623 1.1 gwr * this problem was corrected in the 753/7053. 624 1.1 gwr */ 625 1.1 gwr 626 1.1 gwr for (lcv = 0 ; lcv < XYC_MAXDEV ; lcv++) { 627 1.17 gwr struct xy_softc *oxy; 628 1.17 gwr 629 1.1 gwr oxy = xyc->sc_drives[lcv]; 630 1.69 tsutsui if (oxy == NULL || oxy == xy) 631 1.69 tsutsui continue; 632 1.69 tsutsui if (oxy->drive_type != xy->drive_type) 633 1.69 tsutsui continue; 634 1.1 gwr if (xy->nsect != oxy->nsect || xy->pcyl != oxy->pcyl || 635 1.1 gwr xy->nhead != oxy->nhead) { 636 1.11 christos printf("%s: %s and %s must be the same size!\n", 637 1.69 tsutsui device_xname(xyc->sc_dev), 638 1.69 tsutsui device_xname(xy->sc_dev), 639 1.69 tsutsui device_xname(oxy->sc_dev)); 640 1.1 gwr panic("xy drive size mismatch"); 641 1.1 gwr } 642 1.1 gwr } 643 1.17 gwr 644 1.1 gwr 645 1.1 gwr /* now set the real drive parameters! */ 646 1.1 gwr blk = (xy->nsect - 1) + 647 1.69 tsutsui ((xy->nhead - 1) * xy->nsect) + 648 1.69 tsutsui ((xy->pcyl - 1) * xy->nsect * xy->nhead); 649 1.17 gwr err = xyc_cmd(xyc, XYCMD_SDS, 0, xy->xy_drive, blk, 0, 0, fullmode); 650 1.1 gwr XYC_DONE(xyc, err); 651 1.1 gwr if (err) { 652 1.11 christos printf("%s: write drive size failed: %s\n", 653 1.69 tsutsui device_xname(xy->sc_dev), xyc_e2str(err)); 654 1.1 gwr goto done; 655 1.1 gwr } 656 1.1 gwr newstate = XY_DRIVE_ONLINE; 657 1.1 gwr 658 1.1 gwr /* 659 1.1 gwr * read bad144 table. this table resides on the first sector of the 660 1.1 gwr * last track of the disk (i.e. second cyl of "acyl" area). 661 1.1 gwr */ 662 1.17 gwr blk = (xy->ncyl + xy->acyl - 1) * (xy->nhead * xy->nsect) + 663 1.1 gwr /* last cyl */ 664 1.1 gwr (xy->nhead - 1) * xy->nsect; /* last head */ 665 1.17 gwr err = xyc_cmd(xyc, XYCMD_RD, 0, xy->xy_drive, blk, 1, 666 1.69 tsutsui dvmabuf, fullmode); 667 1.1 gwr XYC_DONE(xyc, err); 668 1.1 gwr if (err) { 669 1.11 christos printf("%s: reading bad144 failed: %s\n", 670 1.69 tsutsui device_xname(xy->sc_dev), xyc_e2str(err)); 671 1.1 gwr goto done; 672 1.1 gwr } 673 1.1 gwr 674 1.1 gwr /* check dkbad for sanity */ 675 1.69 tsutsui dkb = (struct dkbad *)dvmabuf; 676 1.1 gwr for (lcv = 0; lcv < 126; lcv++) { 677 1.1 gwr if ((dkb->bt_bad[lcv].bt_cyl == 0xffff || 678 1.69 tsutsui dkb->bt_bad[lcv].bt_cyl == 0) && 679 1.69 tsutsui dkb->bt_bad[lcv].bt_trksec == 0xffff) 680 1.1 gwr continue; /* blank */ 681 1.1 gwr if (dkb->bt_bad[lcv].bt_cyl >= xy->ncyl) 682 1.1 gwr break; 683 1.1 gwr if ((dkb->bt_bad[lcv].bt_trksec >> 8) >= xy->nhead) 684 1.1 gwr break; 685 1.1 gwr if ((dkb->bt_bad[lcv].bt_trksec & 0xff) >= xy->nsect) 686 1.1 gwr break; 687 1.1 gwr } 688 1.1 gwr if (lcv != 126) { 689 1.11 christos printf("%s: warning: invalid bad144 sector!\n", 690 1.69 tsutsui device_xname(xy->sc_dev)); 691 1.1 gwr } else { 692 1.35 tsutsui memcpy(&xy->dkb, dvmabuf, XYFM_BPS); 693 1.1 gwr } 694 1.1 gwr 695 1.69 tsutsui done: 696 1.1 gwr xy->state = newstate; 697 1.17 gwr dvma_free(dvmabuf, XYFM_BPS); 698 1.1 gwr } 699 1.1 gwr 700 1.1 gwr /* 701 1.1 gwr * { b , c } d e v s w f u n c t i o n s 702 1.1 gwr */ 703 1.1 gwr 704 1.1 gwr /* 705 1.1 gwr * xyclose: close device 706 1.1 gwr */ 707 1.84 tsutsui static int 708 1.53 christos xyclose(dev_t dev, int flag, int fmt, struct lwp *l) 709 1.1 gwr { 710 1.68 tsutsui struct xy_softc *xy = device_lookup_private(&xy_cd, DISKUNIT(dev)); 711 1.69 tsutsui int part = DISKPART(dev); 712 1.1 gwr 713 1.1 gwr /* clear mask bits */ 714 1.1 gwr 715 1.1 gwr switch (fmt) { 716 1.1 gwr case S_IFCHR: 717 1.1 gwr xy->sc_dk.dk_copenmask &= ~(1 << part); 718 1.1 gwr break; 719 1.1 gwr case S_IFBLK: 720 1.1 gwr xy->sc_dk.dk_bopenmask &= ~(1 << part); 721 1.1 gwr break; 722 1.1 gwr } 723 1.1 gwr xy->sc_dk.dk_openmask = xy->sc_dk.dk_copenmask | xy->sc_dk.dk_bopenmask; 724 1.1 gwr 725 1.1 gwr return 0; 726 1.1 gwr } 727 1.1 gwr 728 1.1 gwr /* 729 1.1 gwr * xydump: crash dump system 730 1.1 gwr */ 731 1.84 tsutsui static int 732 1.59 christos xydump(dev_t dev, daddr_t blkno, void *va, size_t sz) 733 1.1 gwr { 734 1.69 tsutsui int unit, part; 735 1.1 gwr struct xy_softc *xy; 736 1.1 gwr 737 1.1 gwr unit = DISKUNIT(dev); 738 1.1 gwr part = DISKPART(dev); 739 1.1 gwr 740 1.68 tsutsui xy = device_lookup_private(&xy_cd, unit); 741 1.69 tsutsui if (xy == NULL) 742 1.69 tsutsui return ENXIO; 743 1.1 gwr 744 1.69 tsutsui printf("%s%c: crash dump not supported (yet)\n", 745 1.69 tsutsui device_xname(xy->sc_dev), 'a' + part); 746 1.1 gwr 747 1.1 gwr return ENXIO; 748 1.1 gwr 749 1.1 gwr /* outline: globals: "dumplo" == sector number of partition to start 750 1.1 gwr * dump at (convert to physical sector with partition table) 751 1.1 gwr * "dumpsize" == size of dump in clicks "physmem" == size of physical 752 1.1 gwr * memory (clicks, ctob() to get bytes) (normal case: dumpsize == 753 1.1 gwr * physmem) 754 1.17 gwr * 755 1.1 gwr * dump a copy of physical memory to the dump device starting at sector 756 1.1 gwr * "dumplo" in the swap partition (make sure > 0). map in pages as 757 1.1 gwr * we go. use polled I/O. 758 1.17 gwr * 759 1.17 gwr * XXX how to handle NON_CONTIG? 760 1.17 gwr */ 761 1.1 gwr } 762 1.1 gwr 763 1.65 elad static enum kauth_device_req 764 1.65 elad xy_getkauthreq(u_char cmd) 765 1.65 elad { 766 1.65 elad enum kauth_device_req req; 767 1.65 elad 768 1.65 elad switch (cmd) { 769 1.65 elad case XYCMD_WR: 770 1.65 elad case XYCMD_WTH: 771 1.65 elad case XYCMD_WFM: 772 1.65 elad case XYCMD_WRH: 773 1.67 elad req = KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITE; 774 1.65 elad break; 775 1.65 elad 776 1.65 elad case XYCMD_RD: 777 1.65 elad case XYCMD_RTH: 778 1.65 elad case XYCMD_RDH: 779 1.67 elad req = KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READ; 780 1.65 elad break; 781 1.65 elad 782 1.65 elad case XYCMD_RDS: 783 1.65 elad case XYCMD_MBD: 784 1.67 elad req = KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF; 785 1.65 elad break; 786 1.65 elad 787 1.65 elad case XYCMD_RST: 788 1.65 elad case XYCMD_SDS: 789 1.65 elad case XYCMD_MBL: 790 1.67 elad req = KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF; 791 1.65 elad break; 792 1.65 elad 793 1.65 elad case XYCMD_NOP: 794 1.65 elad case XYCMD_SK: 795 1.65 elad case XYCMD_ST: 796 1.65 elad case XYCMD_R: 797 1.65 elad default: 798 1.65 elad req = 0; 799 1.65 elad break; 800 1.65 elad } 801 1.65 elad 802 1.69 tsutsui return req; 803 1.65 elad } 804 1.65 elad 805 1.1 gwr /* 806 1.1 gwr * xyioctl: ioctls on XY drives. based on ioctl's of other netbsd disks. 807 1.1 gwr */ 808 1.84 tsutsui static int 809 1.77 christos xyioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 810 1.1 gwr { 811 1.1 gwr struct xy_softc *xy; 812 1.1 gwr struct xd_iocmd *xio; 813 1.1 gwr int error, s, unit; 814 1.1 gwr 815 1.1 gwr unit = DISKUNIT(dev); 816 1.1 gwr 817 1.68 tsutsui xy = device_lookup_private(&xy_cd, unit); 818 1.68 tsutsui if (xy == NULL) 819 1.69 tsutsui return ENXIO; 820 1.1 gwr 821 1.77 christos error = disk_ioctl(&xy->sc_dk, dev, cmd, addr, flag, l); 822 1.77 christos if (error != EPASSTHROUGH) 823 1.77 christos return error; 824 1.77 christos 825 1.1 gwr /* switch on ioctl type */ 826 1.1 gwr 827 1.77 christos switch (cmd) { 828 1.1 gwr case DIOCSBAD: /* set bad144 info */ 829 1.1 gwr if ((flag & FWRITE) == 0) 830 1.1 gwr return EBADF; 831 1.1 gwr s = splbio(); 832 1.35 tsutsui memcpy(&xy->dkb, addr, sizeof(xy->dkb)); 833 1.1 gwr splx(s); 834 1.1 gwr return 0; 835 1.1 gwr 836 1.1 gwr case DIOCSDINFO: /* set disk label */ 837 1.1 gwr if ((flag & FWRITE) == 0) 838 1.1 gwr return EBADF; 839 1.2 thorpej error = setdisklabel(xy->sc_dk.dk_label, 840 1.69 tsutsui (struct disklabel *)addr, /* xy->sc_dk.dk_openmask : */ 0, 841 1.2 thorpej xy->sc_dk.dk_cpulabel); 842 1.1 gwr if (error == 0) { 843 1.1 gwr if (xy->state == XY_DRIVE_NOLABEL) 844 1.1 gwr xy->state = XY_DRIVE_ONLINE; 845 1.1 gwr } 846 1.1 gwr return error; 847 1.1 gwr 848 1.1 gwr case DIOCWLABEL: /* change write status of disk label */ 849 1.1 gwr if ((flag & FWRITE) == 0) 850 1.1 gwr return EBADF; 851 1.69 tsutsui if (*(int *)addr) 852 1.1 gwr xy->flags |= XY_WLABEL; 853 1.1 gwr else 854 1.1 gwr xy->flags &= ~XY_WLABEL; 855 1.1 gwr return 0; 856 1.1 gwr 857 1.1 gwr case DIOCWDINFO: /* write disk label */ 858 1.1 gwr if ((flag & FWRITE) == 0) 859 1.1 gwr return EBADF; 860 1.2 thorpej error = setdisklabel(xy->sc_dk.dk_label, 861 1.69 tsutsui (struct disklabel *)addr, /* xy->sc_dk.dk_openmask : */ 0, 862 1.2 thorpej xy->sc_dk.dk_cpulabel); 863 1.1 gwr if (error == 0) { 864 1.1 gwr if (xy->state == XY_DRIVE_NOLABEL) 865 1.1 gwr xy->state = XY_DRIVE_ONLINE; 866 1.1 gwr 867 1.1 gwr /* Simulate opening partition 0 so write succeeds. */ 868 1.1 gwr xy->sc_dk.dk_openmask |= (1 << 0); 869 1.69 tsutsui error = writedisklabel(MAKEDISKDEV(major(dev), 870 1.69 tsutsui DISKUNIT(dev), RAW_PART), 871 1.2 thorpej xystrategy, xy->sc_dk.dk_label, 872 1.2 thorpej xy->sc_dk.dk_cpulabel); 873 1.1 gwr xy->sc_dk.dk_openmask = 874 1.1 gwr xy->sc_dk.dk_copenmask | xy->sc_dk.dk_bopenmask; 875 1.1 gwr } 876 1.1 gwr return error; 877 1.1 gwr 878 1.65 elad case DIOSXDCMD: { 879 1.65 elad enum kauth_device_req req; 880 1.65 elad 881 1.69 tsutsui xio = (struct xd_iocmd *)addr; 882 1.65 elad req = xy_getkauthreq(xio->cmd); 883 1.65 elad if ((error = kauth_authorize_device_passthru(l->l_cred, 884 1.65 elad dev, req, xio)) != 0) 885 1.69 tsutsui return error; 886 1.69 tsutsui return xyc_ioctlcmd(xy, dev, xio); 887 1.65 elad } 888 1.1 gwr 889 1.1 gwr default: 890 1.1 gwr return ENOTTY; 891 1.1 gwr } 892 1.1 gwr } 893 1.1 gwr 894 1.1 gwr /* 895 1.1 gwr * xyopen: open drive 896 1.1 gwr */ 897 1.84 tsutsui static int 898 1.53 christos xyopen(dev_t dev, int flag, int fmt, struct lwp *l) 899 1.1 gwr { 900 1.17 gwr int err, unit, part, s; 901 1.1 gwr struct xy_softc *xy; 902 1.1 gwr 903 1.1 gwr /* first, could it be a valid target? */ 904 1.1 gwr unit = DISKUNIT(dev); 905 1.68 tsutsui xy = device_lookup_private(&xy_cd, unit); 906 1.68 tsutsui if (xy == NULL) 907 1.69 tsutsui return ENXIO; 908 1.1 gwr part = DISKPART(dev); 909 1.17 gwr err = 0; 910 1.1 gwr 911 1.17 gwr /* 912 1.17 gwr * If some other processing is doing init, sleep. 913 1.17 gwr */ 914 1.17 gwr s = splbio(); 915 1.17 gwr while (xy->state == XY_DRIVE_ATTACHING) { 916 1.17 gwr if (tsleep(&xy->state, PRIBIO, "xyopen", 0)) { 917 1.17 gwr err = EINTR; 918 1.17 gwr goto done; 919 1.17 gwr } 920 1.17 gwr } 921 1.17 gwr /* Do we need to init the drive? */ 922 1.17 gwr if (xy->state == XY_DRIVE_UNKNOWN) { 923 1.17 gwr xy_init(xy); 924 1.17 gwr wakeup(&xy->state); 925 1.17 gwr } 926 1.17 gwr /* Was the init successful? */ 927 1.1 gwr if (xy->state == XY_DRIVE_UNKNOWN) { 928 1.17 gwr err = EIO; 929 1.17 gwr goto done; 930 1.1 gwr } 931 1.17 gwr 932 1.1 gwr /* check for partition */ 933 1.1 gwr if (part != RAW_PART && 934 1.2 thorpej (part >= xy->sc_dk.dk_label->d_npartitions || 935 1.2 thorpej xy->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { 936 1.17 gwr err = ENXIO; 937 1.17 gwr goto done; 938 1.1 gwr } 939 1.17 gwr 940 1.1 gwr /* set open masks */ 941 1.1 gwr switch (fmt) { 942 1.1 gwr case S_IFCHR: 943 1.1 gwr xy->sc_dk.dk_copenmask |= (1 << part); 944 1.1 gwr break; 945 1.1 gwr case S_IFBLK: 946 1.1 gwr xy->sc_dk.dk_bopenmask |= (1 << part); 947 1.1 gwr break; 948 1.1 gwr } 949 1.1 gwr xy->sc_dk.dk_openmask = xy->sc_dk.dk_copenmask | xy->sc_dk.dk_bopenmask; 950 1.1 gwr 951 1.69 tsutsui done: 952 1.17 gwr splx(s); 953 1.69 tsutsui return err; 954 1.1 gwr } 955 1.1 gwr 956 1.84 tsutsui static int 957 1.50 chs xyread(dev_t dev, struct uio *uio, int flags) 958 1.1 gwr { 959 1.1 gwr 960 1.69 tsutsui return physio(xystrategy, NULL, dev, B_READ, minphys, uio); 961 1.1 gwr } 962 1.1 gwr 963 1.84 tsutsui static int 964 1.50 chs xywrite(dev_t dev, struct uio *uio, int flags) 965 1.1 gwr { 966 1.1 gwr 967 1.69 tsutsui return physio(xystrategy, NULL, dev, B_WRITE, minphys, uio); 968 1.1 gwr } 969 1.1 gwr 970 1.1 gwr 971 1.1 gwr /* 972 1.1 gwr * xysize: return size of a partition for a dump 973 1.1 gwr */ 974 1.1 gwr 975 1.84 tsutsui static int 976 1.50 chs xysize(dev_t dev) 977 1.1 gwr { 978 1.1 gwr struct xy_softc *xysc; 979 1.69 tsutsui int unit, part, size, omask; 980 1.1 gwr 981 1.14 pk /* valid unit? */ 982 1.14 pk unit = DISKUNIT(dev); 983 1.68 tsutsui xysc = device_lookup_private(&xy_cd, unit); 984 1.68 tsutsui if (xysc == NULL) 985 1.69 tsutsui return -1; 986 1.1 gwr 987 1.14 pk part = DISKPART(dev); 988 1.14 pk omask = xysc->sc_dk.dk_openmask & (1 << part); 989 1.14 pk 990 1.17 gwr if (omask == 0 && xyopen(dev, 0, S_IFBLK, NULL) != 0) 991 1.69 tsutsui return -1; 992 1.1 gwr 993 1.1 gwr /* do it */ 994 1.2 thorpej if (xysc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) 995 1.1 gwr size = -1; /* only give valid size for swap partitions */ 996 1.1 gwr else 997 1.15 thorpej size = xysc->sc_dk.dk_label->d_partitions[part].p_size * 998 1.15 thorpej (xysc->sc_dk.dk_label->d_secsize / DEV_BSIZE); 999 1.17 gwr if (omask == 0 && xyclose(dev, 0, S_IFBLK, NULL) != 0) 1000 1.69 tsutsui return -1; 1001 1.69 tsutsui return size; 1002 1.1 gwr } 1003 1.1 gwr 1004 1.1 gwr /* 1005 1.1 gwr * xystrategy: buffering system interface to xy. 1006 1.1 gwr */ 1007 1.84 tsutsui static void 1008 1.50 chs xystrategy(struct buf *bp) 1009 1.1 gwr { 1010 1.1 gwr struct xy_softc *xy; 1011 1.69 tsutsui int s, unit; 1012 1.25 thorpej struct disklabel *lp; 1013 1.25 thorpej daddr_t blkno; 1014 1.1 gwr 1015 1.1 gwr unit = DISKUNIT(bp->b_dev); 1016 1.1 gwr 1017 1.1 gwr /* check for live device */ 1018 1.1 gwr 1019 1.68 tsutsui xy = device_lookup_private(&xy_cd, unit); 1020 1.68 tsutsui if (xy == NULL || 1021 1.1 gwr bp->b_blkno < 0 || 1022 1.2 thorpej (bp->b_bcount % xy->sc_dk.dk_label->d_secsize) != 0) { 1023 1.1 gwr bp->b_error = EINVAL; 1024 1.61 ad goto done; 1025 1.1 gwr } 1026 1.1 gwr 1027 1.17 gwr /* There should always be an open first. */ 1028 1.1 gwr if (xy->state == XY_DRIVE_UNKNOWN) { 1029 1.17 gwr bp->b_error = EIO; 1030 1.61 ad goto done; 1031 1.1 gwr } 1032 1.1 gwr if (xy->state != XY_DRIVE_ONLINE && DISKPART(bp->b_dev) != RAW_PART) { 1033 1.1 gwr /* no I/O to unlabeled disks, unless raw partition */ 1034 1.1 gwr bp->b_error = EIO; 1035 1.61 ad goto done; 1036 1.1 gwr } 1037 1.1 gwr /* short circuit zero length request */ 1038 1.1 gwr 1039 1.1 gwr if (bp->b_bcount == 0) 1040 1.1 gwr goto done; 1041 1.1 gwr 1042 1.1 gwr /* check bounds with label (disksubr.c). Determine the size of the 1043 1.1 gwr * transfer, and make sure it is within the boundaries of the 1044 1.1 gwr * partition. Adjust transfer if needed, and signal errors or early 1045 1.1 gwr * completion. */ 1046 1.1 gwr 1047 1.25 thorpej lp = xy->sc_dk.dk_label; 1048 1.25 thorpej 1049 1.46 thorpej if (bounds_check_with_label(&xy->sc_dk, bp, 1050 1.69 tsutsui (xy->flags & XY_WLABEL) != 0) <= 0) 1051 1.1 gwr goto done; 1052 1.1 gwr 1053 1.1 gwr /* 1054 1.25 thorpej * Now convert the block number to absolute and put it in 1055 1.25 thorpej * terms of the device's logical block size. 1056 1.25 thorpej */ 1057 1.25 thorpej blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); 1058 1.25 thorpej if (DISKPART(bp->b_dev) != RAW_PART) 1059 1.25 thorpej blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 1060 1.25 thorpej 1061 1.25 thorpej bp->b_rawblkno = blkno; 1062 1.25 thorpej 1063 1.25 thorpej /* 1064 1.1 gwr * now we know we have a valid buf structure that we need to do I/O 1065 1.1 gwr * on. 1066 1.1 gwr */ 1067 1.1 gwr 1068 1.1 gwr s = splbio(); /* protect the queues */ 1069 1.1 gwr 1070 1.71 yamt bufq_put(xy->xyq, bp); /* XXX disksort_cylinder */ 1071 1.1 gwr 1072 1.1 gwr /* start 'em up */ 1073 1.1 gwr 1074 1.1 gwr xyc_start(xy->parent, NULL); 1075 1.1 gwr 1076 1.1 gwr /* done! */ 1077 1.1 gwr 1078 1.1 gwr splx(s); 1079 1.1 gwr return; 1080 1.1 gwr 1081 1.69 tsutsui done: 1082 1.69 tsutsui /* tells upper layers we are done with this buf */ 1083 1.1 gwr bp->b_resid = bp->b_bcount; 1084 1.1 gwr biodone(bp); 1085 1.1 gwr } 1086 1.1 gwr /* 1087 1.1 gwr * end of {b,c}devsw functions 1088 1.1 gwr */ 1089 1.1 gwr 1090 1.1 gwr /* 1091 1.1 gwr * i n t e r r u p t f u n c t i o n 1092 1.1 gwr * 1093 1.1 gwr * xycintr: hardware interrupt. 1094 1.1 gwr */ 1095 1.83 tsutsui int 1096 1.50 chs xycintr(void *v) 1097 1.1 gwr { 1098 1.1 gwr struct xyc_softc *xycsc = v; 1099 1.1 gwr 1100 1.1 gwr /* kick the event counter */ 1101 1.1 gwr xycsc->sc_intrcnt.ev_count++; 1102 1.1 gwr 1103 1.1 gwr /* remove as many done IOPBs as possible */ 1104 1.1 gwr xyc_remove_iorq(xycsc); 1105 1.1 gwr 1106 1.1 gwr /* start any iorq's already waiting */ 1107 1.1 gwr xyc_start(xycsc, NULL); 1108 1.1 gwr 1109 1.69 tsutsui return 1; 1110 1.1 gwr } 1111 1.1 gwr /* 1112 1.1 gwr * end of interrupt function 1113 1.1 gwr */ 1114 1.1 gwr 1115 1.1 gwr /* 1116 1.1 gwr * i n t e r n a l f u n c t i o n s 1117 1.1 gwr */ 1118 1.1 gwr 1119 1.1 gwr /* 1120 1.1 gwr * xyc_rqinit: fill out the fields of an I/O request 1121 1.1 gwr */ 1122 1.1 gwr 1123 1.83 tsutsui inline void 1124 1.50 chs xyc_rqinit(struct xy_iorq *rq, struct xyc_softc *xyc, struct xy_softc *xy, 1125 1.59 christos int md, u_long blk, int cnt, void *db, struct buf *bp) 1126 1.1 gwr { 1127 1.69 tsutsui 1128 1.1 gwr rq->xyc = xyc; 1129 1.1 gwr rq->xy = xy; 1130 1.1 gwr rq->ttl = XYC_MAXTTL + 10; 1131 1.1 gwr rq->mode = md; 1132 1.1 gwr rq->tries = rq->errno = rq->lasterror = 0; 1133 1.1 gwr rq->blockno = blk; 1134 1.1 gwr rq->sectcnt = cnt; 1135 1.1 gwr rq->dbuf = rq->dbufbase = db; 1136 1.1 gwr rq->buf = bp; 1137 1.1 gwr } 1138 1.1 gwr 1139 1.1 gwr /* 1140 1.1 gwr * xyc_rqtopb: load up an IOPB based on an iorq 1141 1.1 gwr */ 1142 1.1 gwr 1143 1.83 tsutsui void 1144 1.50 chs xyc_rqtopb(struct xy_iorq *iorq, struct xy_iopb *iopb, int cmd, int subfun) 1145 1.1 gwr { 1146 1.1 gwr u_long block, dp; 1147 1.1 gwr 1148 1.1 gwr /* normal IOPB case, standard stuff */ 1149 1.1 gwr 1150 1.1 gwr /* chain bit handled later */ 1151 1.1 gwr iopb->ien = (XY_STATE(iorq->mode) == XY_SUB_POLL) ? 0 : 1; 1152 1.1 gwr iopb->com = cmd; 1153 1.1 gwr iopb->errno = 0; 1154 1.1 gwr iopb->errs = 0; 1155 1.1 gwr iopb->done = 0; 1156 1.1 gwr if (iorq->xy) { 1157 1.1 gwr iopb->unit = iorq->xy->xy_drive; 1158 1.1 gwr iopb->dt = iorq->xy->drive_type; 1159 1.1 gwr } else { 1160 1.1 gwr iopb->unit = 0; 1161 1.1 gwr iopb->dt = 0; 1162 1.1 gwr } 1163 1.1 gwr block = iorq->blockno; 1164 1.1 gwr if (iorq->xy == NULL || block == 0) { 1165 1.1 gwr iopb->sect = iopb->head = iopb->cyl = 0; 1166 1.1 gwr } else { 1167 1.1 gwr iopb->sect = block % iorq->xy->nsect; 1168 1.1 gwr block = block / iorq->xy->nsect; 1169 1.1 gwr iopb->head = block % iorq->xy->nhead; 1170 1.1 gwr block = block / iorq->xy->nhead; 1171 1.1 gwr iopb->cyl = block; 1172 1.1 gwr } 1173 1.1 gwr iopb->scnt = iorq->sectcnt; 1174 1.1 gwr if (iorq->dbuf == NULL) { 1175 1.1 gwr iopb->dataa = 0; 1176 1.1 gwr iopb->datar = 0; 1177 1.1 gwr } else { 1178 1.19 gwr dp = dvma_kvtopa(iorq->dbuf, iorq->xyc->bustype); 1179 1.1 gwr iopb->dataa = (dp & 0xffff); 1180 1.1 gwr iopb->datar = ((dp & 0xff0000) >> 16); 1181 1.1 gwr } 1182 1.1 gwr iopb->subfn = subfun; 1183 1.1 gwr } 1184 1.1 gwr 1185 1.1 gwr 1186 1.1 gwr /* 1187 1.1 gwr * xyc_unbusy: wait for the xyc to go unbusy, or timeout. 1188 1.1 gwr */ 1189 1.1 gwr 1190 1.83 tsutsui int 1191 1.50 chs xyc_unbusy(struct xyc *xyc, int del) 1192 1.1 gwr { 1193 1.69 tsutsui 1194 1.1 gwr while (del-- > 0) { 1195 1.1 gwr if ((xyc->xyc_csr & XYC_GBSY) == 0) 1196 1.1 gwr break; 1197 1.1 gwr DELAY(1); 1198 1.1 gwr } 1199 1.69 tsutsui return del == 0 ? XY_ERR_FAIL : XY_ERR_AOK; 1200 1.1 gwr } 1201 1.1 gwr 1202 1.1 gwr /* 1203 1.1 gwr * xyc_cmd: front end for POLL'd and WAIT'd commands. Returns 0 or error. 1204 1.34 wiz * note that NORM requests are handled separately. 1205 1.1 gwr */ 1206 1.83 tsutsui int 1207 1.50 chs xyc_cmd(struct xyc_softc *xycsc, int cmd, int subfn, int unit, int block, 1208 1.50 chs int scnt, char *dptr, int fullmode) 1209 1.1 gwr { 1210 1.1 gwr struct xy_iorq *iorq = xycsc->ciorq; 1211 1.1 gwr struct xy_iopb *iopb = xycsc->ciopb; 1212 1.17 gwr int submode = XY_STATE(fullmode); 1213 1.1 gwr 1214 1.1 gwr /* 1215 1.1 gwr * is someone else using the control iopq wait for it if we can 1216 1.1 gwr */ 1217 1.69 tsutsui start: 1218 1.1 gwr if (submode == XY_SUB_WAIT && XY_STATE(iorq->mode) != XY_SUB_FREE) { 1219 1.17 gwr if (tsleep(iorq, PRIBIO, "xyc_cmd", 0)) 1220 1.69 tsutsui return XY_ERR_FAIL; 1221 1.1 gwr goto start; 1222 1.1 gwr } 1223 1.1 gwr 1224 1.1 gwr if (XY_STATE(iorq->mode) != XY_SUB_FREE) { 1225 1.1 gwr DELAY(1000000); /* XY_SUB_POLL: steal the iorq */ 1226 1.1 gwr iorq->mode = XY_SUB_FREE; 1227 1.69 tsutsui printf("%s: stole control iopb\n", device_xname(xycsc->sc_dev)); 1228 1.1 gwr } 1229 1.1 gwr 1230 1.1 gwr /* init iorq/iopb */ 1231 1.1 gwr 1232 1.1 gwr xyc_rqinit(iorq, xycsc, 1233 1.1 gwr (unit == XYC_NOUNIT) ? NULL : xycsc->sc_drives[unit], 1234 1.1 gwr fullmode, block, scnt, dptr, NULL); 1235 1.1 gwr 1236 1.1 gwr /* load IOPB from iorq */ 1237 1.1 gwr 1238 1.1 gwr xyc_rqtopb(iorq, iopb, cmd, subfn); 1239 1.1 gwr 1240 1.1 gwr /* submit it for processing */ 1241 1.1 gwr 1242 1.1 gwr xyc_submit_iorq(xycsc, iorq, fullmode); /* error code will be in iorq */ 1243 1.1 gwr 1244 1.69 tsutsui return XY_ERR_AOK; 1245 1.1 gwr } 1246 1.1 gwr 1247 1.1 gwr /* 1248 1.1 gwr * xyc_startbuf 1249 1.1 gwr * start a buffer for running 1250 1.1 gwr */ 1251 1.1 gwr 1252 1.83 tsutsui int 1253 1.50 chs xyc_startbuf(struct xyc_softc *xycsc, struct xy_softc *xysc, struct buf *bp) 1254 1.1 gwr { 1255 1.1 gwr struct xy_iorq *iorq; 1256 1.1 gwr struct xy_iopb *iopb; 1257 1.17 gwr u_long block; 1258 1.59 christos void *dbuf; 1259 1.1 gwr 1260 1.1 gwr iorq = xysc->xyrq; 1261 1.1 gwr iopb = iorq->iopb; 1262 1.1 gwr 1263 1.1 gwr /* get buf */ 1264 1.1 gwr 1265 1.17 gwr if (bp == NULL) 1266 1.69 tsutsui panic("%s null buf", __func__); 1267 1.1 gwr 1268 1.1 gwr #ifdef XYC_DEBUG 1269 1.73 christos int partno = DISKPART(bp->b_dev); 1270 1.69 tsutsui printf("%s: %s%c: %s block %d\n", __func__, device_xname(xysc->sc_dev), 1271 1.69 tsutsui 'a' + partno, (bp->b_flags & B_READ) ? "read" : "write", 1272 1.69 tsutsui (int)bp->b_blkno); 1273 1.11 christos printf("xyc_startbuf: b_bcount %d, b_data 0x%x\n", 1274 1.1 gwr bp->b_bcount, bp->b_data); 1275 1.1 gwr #endif 1276 1.1 gwr 1277 1.1 gwr /* 1278 1.25 thorpej * load request. 1279 1.17 gwr * 1280 1.1 gwr * also, note that there are two kinds of buf structures, those with 1281 1.1 gwr * B_PHYS set and those without B_PHYS. if B_PHYS is set, then it is 1282 1.1 gwr * a raw I/O (to a cdevsw) and we are doing I/O directly to the users' 1283 1.1 gwr * buffer which has already been mapped into DVMA space. (Not on sun3) 1284 1.1 gwr * However, if B_PHYS is not set, then the buffer is a normal system 1285 1.1 gwr * buffer which does *not* live in DVMA space. In that case we call 1286 1.1 gwr * dvma_mapin to map it into DVMA space so we can do the DMA to it. 1287 1.17 gwr * 1288 1.69 tsutsui * in cases where we do a dvma_mapin, note that iorq points to the 1289 1.69 tsutsui * buffer as mapped into DVMA space, where as the bp->b_data points 1290 1.69 tsutsui * to its non-DVMA mapping. 1291 1.1 gwr * 1292 1.1 gwr * XXX - On the sun3, B_PHYS does NOT mean the buffer is mapped 1293 1.1 gwr * into dvma space, only that it was remapped into the kernel. 1294 1.1 gwr * We ALWAYS have to remap the kernel buf into DVMA space. 1295 1.1 gwr * (It is done inexpensively, using whole segments!) 1296 1.1 gwr */ 1297 1.1 gwr 1298 1.25 thorpej block = bp->b_rawblkno; 1299 1.1 gwr 1300 1.17 gwr dbuf = dvma_mapin(bp->b_data, bp->b_bcount, 0); 1301 1.1 gwr if (dbuf == NULL) { /* out of DVMA space */ 1302 1.17 gwr printf("%s: warning: out of DVMA space\n", 1303 1.69 tsutsui device_xname(xycsc->sc_dev)); 1304 1.69 tsutsui return XY_ERR_FAIL; /* XXX: need some sort of 1305 1.1 gwr * call-back scheme here? */ 1306 1.1 gwr } 1307 1.1 gwr 1308 1.1 gwr /* init iorq and load iopb from it */ 1309 1.1 gwr 1310 1.1 gwr xyc_rqinit(iorq, xycsc, xysc, XY_SUB_NORM | XY_MODE_VERBO, block, 1311 1.1 gwr bp->b_bcount / XYFM_BPS, dbuf, bp); 1312 1.1 gwr 1313 1.1 gwr xyc_rqtopb(iorq, iopb, (bp->b_flags & B_READ) ? XYCMD_RD : XYCMD_WR, 0); 1314 1.1 gwr 1315 1.5 chuck /* Instrumentation. */ 1316 1.5 chuck disk_busy(&xysc->sc_dk); 1317 1.5 chuck 1318 1.69 tsutsui return XY_ERR_AOK; 1319 1.1 gwr } 1320 1.1 gwr 1321 1.1 gwr 1322 1.1 gwr /* 1323 1.1 gwr * xyc_submit_iorq: submit an iorq for processing. returns XY_ERR_AOK 1324 1.1 gwr * if ok. if it fail returns an error code. type is XY_SUB_*. 1325 1.1 gwr * 1326 1.1 gwr * note: caller frees iorq in all cases except NORM 1327 1.1 gwr * 1328 1.1 gwr * return value: 1329 1.1 gwr * NORM: XY_AOK (req pending), XY_FAIL (couldn't submit request) 1330 1.1 gwr * WAIT: XY_AOK (success), <error-code> (failed) 1331 1.1 gwr * POLL: <same as WAIT> 1332 1.1 gwr * NOQ : <same as NORM> 1333 1.1 gwr * 1334 1.1 gwr * there are three sources for i/o requests: 1335 1.1 gwr * [1] xystrategy: normal block I/O, using "struct buf" system. 1336 1.1 gwr * [2] autoconfig/crash dump: these are polled I/O requests, no interrupts. 1337 1.1 gwr * [3] open/ioctl: these are I/O requests done in the context of a process, 1338 1.1 gwr * and the process should block until they are done. 1339 1.1 gwr * 1340 1.1 gwr * software state is stored in the iorq structure. each iorq has an 1341 1.1 gwr * iopb structure. the hardware understands the iopb structure. 1342 1.1 gwr * every command must go through an iopb. a 450 handles one iopb at a 1343 1.1 gwr * time, where as a 451 can take them in chains. [the 450 claims it 1344 1.1 gwr * can handle chains, but is appears to be buggy...] iopb are allocated 1345 1.1 gwr * in DVMA space at boot up time. each disk gets one iopb, and the 1346 1.17 gwr * controller gets one (for POLL and WAIT commands). what happens if 1347 1.17 gwr * the iopb is busy? for i/o type [1], the buffers are queued at the 1348 1.17 gwr * "buff" layer and * picked up later by the interrupt routine. for case 1349 1.1 gwr * [2] we can only be blocked if there is a WAIT type I/O request being 1350 1.1 gwr * run. since this can only happen when we are crashing, we wait a sec 1351 1.1 gwr * and then steal the IOPB. for case [3] the process can sleep 1352 1.48 wiz * on the iorq free list until some iopbs are available. 1353 1.1 gwr */ 1354 1.1 gwr 1355 1.83 tsutsui int 1356 1.50 chs xyc_submit_iorq(struct xyc_softc *xycsc, struct xy_iorq *iorq, int type) 1357 1.1 gwr { 1358 1.1 gwr struct xy_iopb *iopb; 1359 1.1 gwr u_long iopbaddr; 1360 1.1 gwr 1361 1.1 gwr #ifdef XYC_DEBUG 1362 1.69 tsutsui printf("%s(%s, addr=0x%x, type=%d)\n", __func__, 1363 1.69 tsutsui device_xname(xycsc->sc_dev), iorq, type); 1364 1.1 gwr #endif 1365 1.1 gwr 1366 1.1 gwr /* first check and see if controller is busy */ 1367 1.1 gwr if ((xycsc->xyc->xyc_csr & XYC_GBSY) != 0) { 1368 1.1 gwr #ifdef XYC_DEBUG 1369 1.69 tsutsui printf("%s: XYC not ready (BUSY)\n", __func__); 1370 1.1 gwr #endif 1371 1.1 gwr if (type == XY_SUB_NOQ) 1372 1.69 tsutsui return XY_ERR_FAIL; /* failed */ 1373 1.1 gwr switch (type) { 1374 1.1 gwr case XY_SUB_NORM: 1375 1.1 gwr return XY_ERR_AOK; /* success */ 1376 1.1 gwr case XY_SUB_WAIT: 1377 1.1 gwr while (iorq->iopb->done == 0) { 1378 1.69 tsutsui (void)tsleep(iorq, PRIBIO, "xyciorq", 0); 1379 1.1 gwr } 1380 1.1 gwr return (iorq->errno); 1381 1.1 gwr case XY_SUB_POLL: /* steal controller */ 1382 1.1 gwr iopbaddr = xycsc->xyc->xyc_rsetup; /* RESET */ 1383 1.69 tsutsui if (xyc_unbusy(xycsc->xyc, XYC_RESETUSEC) == 1384 1.69 tsutsui XY_ERR_FAIL) 1385 1.69 tsutsui panic("%s: stuck xyc", __func__); 1386 1.11 christos printf("%s: stole controller\n", 1387 1.69 tsutsui device_xname(xycsc->sc_dev)); 1388 1.1 gwr break; 1389 1.1 gwr default: 1390 1.69 tsutsui panic("%s adding", __func__); 1391 1.1 gwr } 1392 1.1 gwr } 1393 1.1 gwr 1394 1.1 gwr iopb = xyc_chain(xycsc, iorq); /* build chain */ 1395 1.1 gwr if (iopb == NULL) { /* nothing doing? */ 1396 1.17 gwr if (type == XY_SUB_NORM || type == XY_SUB_NOQ) 1397 1.69 tsutsui return XY_ERR_AOK; 1398 1.38 provos panic("xyc_submit_iorq: xyc_chain failed!"); 1399 1.1 gwr } 1400 1.19 gwr iopbaddr = dvma_kvtopa(iopb, xycsc->bustype); 1401 1.17 gwr 1402 1.1 gwr XYC_GO(xycsc->xyc, iopbaddr); 1403 1.1 gwr 1404 1.1 gwr /* command now running, wrap it up */ 1405 1.1 gwr switch (type) { 1406 1.1 gwr case XY_SUB_NORM: 1407 1.1 gwr case XY_SUB_NOQ: 1408 1.69 tsutsui return XY_ERR_AOK; /* success */ 1409 1.1 gwr case XY_SUB_WAIT: 1410 1.1 gwr while (iorq->iopb->done == 0) { 1411 1.69 tsutsui (void)tsleep(iorq, PRIBIO, "xyciorq", 0); 1412 1.1 gwr } 1413 1.69 tsutsui return iorq->errno; 1414 1.1 gwr case XY_SUB_POLL: 1415 1.69 tsutsui return xyc_piodriver(xycsc, iorq); 1416 1.1 gwr default: 1417 1.69 tsutsui panic("%s wrap up", __func__); 1418 1.1 gwr } 1419 1.69 tsutsui panic("%s impossible", __func__); 1420 1.1 gwr return 0; /* not reached */ 1421 1.1 gwr } 1422 1.1 gwr 1423 1.1 gwr 1424 1.1 gwr /* 1425 1.1 gwr * xyc_chain: build a chain. return dvma address of first element in 1426 1.1 gwr * the chain. iorq != NULL: means we only want that item on the chain. 1427 1.1 gwr */ 1428 1.1 gwr 1429 1.1 gwr struct xy_iopb * 1430 1.50 chs xyc_chain(struct xyc_softc *xycsc, struct xy_iorq *iorq) 1431 1.1 gwr { 1432 1.17 gwr int togo, chain, hand; 1433 1.17 gwr struct xy_iopb *iopb, *prev_iopb; 1434 1.50 chs 1435 1.35 tsutsui memset(xycsc->xy_chain, 0, sizeof(xycsc->xy_chain)); 1436 1.17 gwr 1437 1.17 gwr /* 1438 1.17 gwr * promote control IOPB to the top 1439 1.17 gwr */ 1440 1.17 gwr if (iorq == NULL) { 1441 1.17 gwr if ((XY_STATE(xycsc->reqs[XYC_CTLIOPB].mode) == XY_SUB_POLL || 1442 1.69 tsutsui XY_STATE(xycsc->reqs[XYC_CTLIOPB].mode) == XY_SUB_WAIT) && 1443 1.69 tsutsui xycsc->iopbase[XYC_CTLIOPB].done == 0) 1444 1.69 tsutsui iorq = &xycsc->reqs[XYC_CTLIOPB]; 1445 1.17 gwr } 1446 1.50 chs 1447 1.17 gwr /* 1448 1.17 gwr * special case: if iorq != NULL then we have a POLL or WAIT request. 1449 1.17 gwr * we let these take priority and do them first. 1450 1.17 gwr */ 1451 1.17 gwr if (iorq) { 1452 1.17 gwr xycsc->xy_chain[0] = iorq; 1453 1.17 gwr iorq->iopb->chen = 0; 1454 1.69 tsutsui return iorq->iopb; 1455 1.17 gwr } 1456 1.17 gwr 1457 1.17 gwr /* 1458 1.17 gwr * NORM case: do round robin and maybe chain (if allowed and possible) 1459 1.17 gwr */ 1460 1.17 gwr 1461 1.17 gwr chain = 0; 1462 1.17 gwr hand = xycsc->xy_hand; 1463 1.17 gwr xycsc->xy_hand = (xycsc->xy_hand + 1) % XYC_MAXIOPB; 1464 1.17 gwr 1465 1.69 tsutsui for (togo = XYC_MAXIOPB ; togo > 0 ; 1466 1.69 tsutsui togo--, hand = (hand + 1) % XYC_MAXIOPB) { 1467 1.17 gwr 1468 1.17 gwr if (XY_STATE(xycsc->reqs[hand].mode) != XY_SUB_NORM || 1469 1.69 tsutsui xycsc->iopbase[hand].done) 1470 1.17 gwr continue; /* not ready-for-i/o */ 1471 1.17 gwr 1472 1.17 gwr xycsc->xy_chain[chain] = &xycsc->reqs[hand]; 1473 1.17 gwr iopb = xycsc->xy_chain[chain]->iopb; 1474 1.17 gwr iopb->chen = 0; 1475 1.17 gwr if (chain != 0) { /* adding a link to a chain? */ 1476 1.17 gwr prev_iopb = xycsc->xy_chain[chain-1]->iopb; 1477 1.17 gwr prev_iopb->chen = 1; 1478 1.17 gwr prev_iopb->nxtiopb = 0xffff & 1479 1.69 tsutsui dvma_kvtopa(iopb, xycsc->bustype); 1480 1.17 gwr } else { /* head of chain */ 1481 1.17 gwr iorq = xycsc->xy_chain[chain]; 1482 1.17 gwr } 1483 1.17 gwr chain++; 1484 1.69 tsutsui if (xycsc->no_ols) 1485 1.69 tsutsui break; /* quit if chaining dis-allowed */ 1486 1.17 gwr } 1487 1.69 tsutsui return iorq ? iorq->iopb : NULL; 1488 1.1 gwr } 1489 1.1 gwr 1490 1.1 gwr /* 1491 1.1 gwr * xyc_piodriver 1492 1.1 gwr * 1493 1.1 gwr * programmed i/o driver. this function takes over the computer 1494 1.1 gwr * and drains off the polled i/o request. it returns the status of the iorq 1495 1.17 gwr * the caller is interesting in. 1496 1.1 gwr */ 1497 1.83 tsutsui int 1498 1.50 chs xyc_piodriver(struct xyc_softc *xycsc, struct xy_iorq *iorq) 1499 1.1 gwr { 1500 1.69 tsutsui int nreset = 0; 1501 1.69 tsutsui int retval = 0; 1502 1.1 gwr u_long res; 1503 1.17 gwr 1504 1.1 gwr #ifdef XYC_DEBUG 1505 1.69 tsutsui printf("%s(%s, 0x%x)\n", __func__, device_xname(xycsc->sc_dev), iorq); 1506 1.1 gwr #endif 1507 1.1 gwr 1508 1.1 gwr while (iorq->iopb->done == 0) { 1509 1.1 gwr 1510 1.1 gwr res = xyc_unbusy(xycsc->xyc, XYC_MAXTIME); 1511 1.1 gwr 1512 1.1 gwr /* we expect some progress soon */ 1513 1.1 gwr if (res == XY_ERR_FAIL && nreset >= 2) { 1514 1.1 gwr xyc_reset(xycsc, 0, XY_RSET_ALL, XY_ERR_FAIL, 0); 1515 1.1 gwr #ifdef XYC_DEBUG 1516 1.69 tsutsui printf("%s: timeout\n", __func__); 1517 1.1 gwr #endif 1518 1.69 tsutsui return XY_ERR_FAIL; 1519 1.1 gwr } 1520 1.1 gwr if (res == XY_ERR_FAIL) { 1521 1.1 gwr if (xyc_reset(xycsc, 0, 1522 1.69 tsutsui (nreset++ == 0) ? XY_RSET_NONE : iorq, 1523 1.69 tsutsui XY_ERR_FAIL, 0) == XY_ERR_FAIL) 1524 1.69 tsutsui return XY_ERR_FAIL; /* flushes all but POLL 1525 1.1 gwr * requests, resets */ 1526 1.1 gwr continue; 1527 1.1 gwr } 1528 1.1 gwr 1529 1.1 gwr xyc_remove_iorq(xycsc); /* may resubmit request */ 1530 1.1 gwr 1531 1.1 gwr if (iorq->iopb->done == 0) 1532 1.1 gwr xyc_start(xycsc, iorq); 1533 1.1 gwr } 1534 1.1 gwr 1535 1.1 gwr /* get return value */ 1536 1.1 gwr 1537 1.1 gwr retval = iorq->errno; 1538 1.1 gwr 1539 1.1 gwr #ifdef XYC_DEBUG 1540 1.69 tsutsui printf("%s: done, retval = 0x%x (%s)\n", __func__, 1541 1.1 gwr iorq->errno, xyc_e2str(iorq->errno)); 1542 1.1 gwr #endif 1543 1.1 gwr 1544 1.1 gwr /* start up any bufs that have queued */ 1545 1.1 gwr 1546 1.17 gwr xyc_start(xycsc, NULL); 1547 1.1 gwr 1548 1.69 tsutsui return retval; 1549 1.1 gwr } 1550 1.1 gwr 1551 1.1 gwr /* 1552 1.1 gwr * xyc_xyreset: reset one drive. NOTE: assumes xyc was just reset. 1553 1.1 gwr * we steal iopb[XYC_CTLIOPB] for this, but we put it back when we are done. 1554 1.1 gwr */ 1555 1.83 tsutsui void 1556 1.50 chs xyc_xyreset(struct xyc_softc *xycsc, struct xy_softc *xysc) 1557 1.1 gwr { 1558 1.1 gwr struct xy_iopb tmpiopb; 1559 1.1 gwr u_long addr; 1560 1.69 tsutsui int del; 1561 1.35 tsutsui memcpy(&tmpiopb, xycsc->ciopb, sizeof(tmpiopb)); 1562 1.1 gwr xycsc->ciopb->chen = xycsc->ciopb->done = xycsc->ciopb->errs = 0; 1563 1.1 gwr xycsc->ciopb->ien = 0; 1564 1.1 gwr xycsc->ciopb->com = XYCMD_RST; 1565 1.1 gwr xycsc->ciopb->unit = xysc->xy_drive; 1566 1.19 gwr addr = dvma_kvtopa(xycsc->ciopb, xycsc->bustype); 1567 1.1 gwr 1568 1.1 gwr XYC_GO(xycsc->xyc, addr); 1569 1.1 gwr 1570 1.1 gwr del = XYC_RESETUSEC; 1571 1.1 gwr while (del > 0) { 1572 1.69 tsutsui if ((xycsc->xyc->xyc_csr & XYC_GBSY) == 0) 1573 1.69 tsutsui break; 1574 1.1 gwr DELAY(1); 1575 1.1 gwr del--; 1576 1.1 gwr } 1577 1.1 gwr 1578 1.1 gwr if (del <= 0 || xycsc->ciopb->errs) { 1579 1.69 tsutsui printf("%s: off-line: %s\n", device_xname(xycsc->sc_dev), 1580 1.1 gwr xyc_e2str(xycsc->ciopb->errno)); 1581 1.1 gwr del = xycsc->xyc->xyc_rsetup; 1582 1.1 gwr if (xyc_unbusy(xycsc->xyc, XYC_RESETUSEC) == XY_ERR_FAIL) 1583 1.69 tsutsui panic("%s", __func__); 1584 1.1 gwr } else { 1585 1.7 chuck xycsc->xyc->xyc_csr = XYC_IPND; /* clear IPND */ 1586 1.1 gwr } 1587 1.35 tsutsui memcpy(xycsc->ciopb, &tmpiopb, sizeof(tmpiopb)); 1588 1.1 gwr } 1589 1.1 gwr 1590 1.1 gwr 1591 1.1 gwr /* 1592 1.1 gwr * xyc_reset: reset everything: requests are marked as errors except 1593 1.1 gwr * a polled request (which is resubmitted) 1594 1.1 gwr */ 1595 1.83 tsutsui int 1596 1.50 chs xyc_reset(struct xyc_softc *xycsc, int quiet, struct xy_iorq *blastmode, 1597 1.50 chs int error, struct xy_softc *xysc) 1598 1.1 gwr { 1599 1.69 tsutsui int del = 0, lcv, retval = XY_ERR_AOK; 1600 1.1 gwr struct xy_iorq *iorq; 1601 1.1 gwr 1602 1.1 gwr /* soft reset hardware */ 1603 1.1 gwr 1604 1.69 tsutsui if (quiet == 0) 1605 1.69 tsutsui printf("%s: soft reset\n", device_xname(xycsc->sc_dev)); 1606 1.1 gwr del = xycsc->xyc->xyc_rsetup; 1607 1.1 gwr del = xyc_unbusy(xycsc->xyc, XYC_RESETUSEC); 1608 1.1 gwr if (del == XY_ERR_FAIL) { 1609 1.1 gwr blastmode = XY_RSET_ALL; /* dead, flush all requests */ 1610 1.1 gwr retval = XY_ERR_FAIL; 1611 1.1 gwr } 1612 1.1 gwr if (xysc) 1613 1.1 gwr xyc_xyreset(xycsc, xysc); 1614 1.1 gwr 1615 1.1 gwr /* fix queues based on "blast-mode" */ 1616 1.1 gwr 1617 1.1 gwr for (lcv = 0; lcv < XYC_MAXIOPB; lcv++) { 1618 1.1 gwr iorq = &xycsc->reqs[lcv]; 1619 1.1 gwr 1620 1.1 gwr if (XY_STATE(iorq->mode) != XY_SUB_POLL && 1621 1.1 gwr XY_STATE(iorq->mode) != XY_SUB_WAIT && 1622 1.1 gwr XY_STATE(iorq->mode) != XY_SUB_NORM) 1623 1.1 gwr /* is it active? */ 1624 1.1 gwr continue; 1625 1.1 gwr 1626 1.17 gwr if (blastmode == XY_RSET_ALL || 1627 1.69 tsutsui blastmode != iorq) { 1628 1.1 gwr /* failed */ 1629 1.1 gwr iorq->errno = error; 1630 1.1 gwr xycsc->iopbase[lcv].done = xycsc->iopbase[lcv].errs = 1; 1631 1.1 gwr switch (XY_STATE(iorq->mode)) { 1632 1.1 gwr case XY_SUB_NORM: 1633 1.69 tsutsui iorq->buf->b_error = EIO; 1634 1.69 tsutsui iorq->buf->b_resid = iorq->sectcnt * XYFM_BPS; 1635 1.1 gwr /* Sun3: map/unmap regardless of B_PHYS */ 1636 1.1 gwr dvma_mapout(iorq->dbufbase, 1637 1.69 tsutsui iorq->buf->b_bcount); 1638 1.71 yamt (void)bufq_get(iorq->xy->xyq); 1639 1.69 tsutsui disk_unbusy(&iorq->xy->sc_dk, 1640 1.69 tsutsui (iorq->buf->b_bcount - iorq->buf->b_resid), 1641 1.69 tsutsui (iorq->buf->b_flags & B_READ)); 1642 1.69 tsutsui biodone(iorq->buf); 1643 1.69 tsutsui iorq->mode = XY_SUB_FREE; 1644 1.69 tsutsui break; 1645 1.1 gwr case XY_SUB_WAIT: 1646 1.69 tsutsui wakeup(iorq); 1647 1.1 gwr case XY_SUB_POLL: 1648 1.69 tsutsui iorq->mode = 1649 1.69 tsutsui XY_NEWSTATE(iorq->mode, XY_SUB_DONE); 1650 1.69 tsutsui break; 1651 1.1 gwr } 1652 1.1 gwr 1653 1.1 gwr } else { 1654 1.1 gwr 1655 1.1 gwr /* resubmit, no need to do anything here */ 1656 1.1 gwr } 1657 1.1 gwr } 1658 1.1 gwr 1659 1.1 gwr /* 1660 1.1 gwr * now, if stuff is waiting, start it. 1661 1.1 gwr * since we just reset it should go 1662 1.1 gwr */ 1663 1.1 gwr xyc_start(xycsc, NULL); 1664 1.1 gwr 1665 1.69 tsutsui return retval; 1666 1.1 gwr } 1667 1.1 gwr 1668 1.1 gwr /* 1669 1.1 gwr * xyc_start: start waiting buffers 1670 1.1 gwr */ 1671 1.1 gwr 1672 1.83 tsutsui void 1673 1.50 chs xyc_start(struct xyc_softc *xycsc, struct xy_iorq *iorq) 1674 1.1 gwr { 1675 1.1 gwr int lcv; 1676 1.1 gwr struct xy_softc *xy; 1677 1.1 gwr 1678 1.1 gwr if (iorq == NULL) { 1679 1.1 gwr for (lcv = 0; lcv < XYC_MAXDEV ; lcv++) { 1680 1.69 tsutsui if ((xy = xycsc->sc_drives[lcv]) == NULL) 1681 1.69 tsutsui continue; 1682 1.71 yamt if (bufq_peek(xy->xyq) == NULL) 1683 1.69 tsutsui continue; 1684 1.69 tsutsui if (xy->xyrq->mode != XY_SUB_FREE) 1685 1.69 tsutsui continue; 1686 1.71 yamt xyc_startbuf(xycsc, xy, bufq_peek(xy->xyq)); 1687 1.1 gwr } 1688 1.1 gwr } 1689 1.1 gwr xyc_submit_iorq(xycsc, iorq, XY_SUB_NOQ); 1690 1.1 gwr } 1691 1.1 gwr 1692 1.1 gwr /* 1693 1.17 gwr * xyc_remove_iorq: remove "done" IOPB's. 1694 1.1 gwr */ 1695 1.1 gwr 1696 1.83 tsutsui int 1697 1.50 chs xyc_remove_iorq(struct xyc_softc *xycsc) 1698 1.1 gwr { 1699 1.69 tsutsui int errno, rq, comm, errs; 1700 1.1 gwr struct xyc *xyc = xycsc->xyc; 1701 1.69 tsutsui u_long addr; 1702 1.1 gwr struct xy_iopb *iopb; 1703 1.1 gwr struct xy_iorq *iorq; 1704 1.1 gwr struct buf *bp; 1705 1.1 gwr 1706 1.1 gwr if (xyc->xyc_csr & XYC_DERR) { 1707 1.1 gwr /* 1708 1.1 gwr * DOUBLE ERROR: should never happen under normal use. This 1709 1.1 gwr * error is so bad, you can't even tell which IOPB is bad, so 1710 1.1 gwr * we dump them all. 1711 1.1 gwr */ 1712 1.1 gwr errno = XY_ERR_DERR; 1713 1.69 tsutsui printf("%s: DOUBLE ERROR!\n", device_xname(xycsc->sc_dev)); 1714 1.1 gwr if (xyc_reset(xycsc, 0, XY_RSET_ALL, errno, 0) != XY_ERR_AOK) { 1715 1.11 christos printf("%s: soft reset failed!\n", 1716 1.69 tsutsui device_xname(xycsc->sc_dev)); 1717 1.69 tsutsui panic("%s: controller DEAD", __func__); 1718 1.1 gwr } 1719 1.69 tsutsui return XY_ERR_AOK; 1720 1.1 gwr } 1721 1.1 gwr 1722 1.1 gwr /* 1723 1.1 gwr * get iopb that is done, loop down the chain 1724 1.1 gwr */ 1725 1.1 gwr 1726 1.1 gwr if (xyc->xyc_csr & XYC_ERR) { 1727 1.7 chuck xyc->xyc_csr = XYC_ERR; /* clear error condition */ 1728 1.1 gwr } 1729 1.1 gwr if (xyc->xyc_csr & XYC_IPND) { 1730 1.7 chuck xyc->xyc_csr = XYC_IPND; /* clear interrupt */ 1731 1.1 gwr } 1732 1.1 gwr 1733 1.1 gwr for (rq = 0; rq < XYC_MAXIOPB; rq++) { 1734 1.1 gwr iorq = xycsc->xy_chain[rq]; 1735 1.1 gwr if (iorq == NULL) break; /* done ! */ 1736 1.1 gwr if (iorq->mode == 0 || XY_STATE(iorq->mode) == XY_SUB_DONE) 1737 1.1 gwr continue; /* free, or done */ 1738 1.1 gwr iopb = iorq->iopb; 1739 1.1 gwr if (iopb->done == 0) 1740 1.1 gwr continue; /* not done yet */ 1741 1.1 gwr 1742 1.1 gwr comm = iopb->com; 1743 1.1 gwr errs = iopb->errs; 1744 1.1 gwr 1745 1.1 gwr if (errs) 1746 1.1 gwr iorq->errno = iopb->errno; 1747 1.1 gwr else 1748 1.1 gwr iorq->errno = 0; 1749 1.1 gwr 1750 1.1 gwr /* handle non-fatal errors */ 1751 1.1 gwr 1752 1.1 gwr if (errs && 1753 1.1 gwr xyc_error(xycsc, iorq, iopb, comm) == XY_ERR_AOK) 1754 1.1 gwr continue; /* AOK: we resubmitted it */ 1755 1.1 gwr 1756 1.1 gwr 1757 1.1 gwr /* this iorq is now done (hasn't been restarted or anything) */ 1758 1.1 gwr 1759 1.1 gwr if ((iorq->mode & XY_MODE_VERBO) && iorq->lasterror) 1760 1.1 gwr xyc_perror(iorq, iopb, 0); 1761 1.1 gwr 1762 1.1 gwr /* now, if read/write check to make sure we got all the data 1763 1.1 gwr * we needed. (this may not be the case if we got an error in 1764 1.1 gwr * the middle of a multisector request). */ 1765 1.1 gwr 1766 1.1 gwr if ((iorq->mode & XY_MODE_B144) != 0 && errs == 0 && 1767 1.1 gwr (comm == XYCMD_RD || comm == XYCMD_WR)) { 1768 1.1 gwr /* we just successfully processed a bad144 sector 1769 1.1 gwr * note: if we are in bad 144 mode, the pointers have 1770 1.1 gwr * been advanced already (see above) and are pointing 1771 1.1 gwr * at the bad144 sector. to exit bad144 mode, we 1772 1.1 gwr * must advance the pointers 1 sector and issue a new 1773 1.1 gwr * request if there are still sectors left to process 1774 1.17 gwr * 1775 1.1 gwr */ 1776 1.1 gwr XYC_ADVANCE(iorq, 1); /* advance 1 sector */ 1777 1.1 gwr 1778 1.1 gwr /* exit b144 mode */ 1779 1.1 gwr iorq->mode = iorq->mode & (~XY_MODE_B144); 1780 1.1 gwr 1781 1.1 gwr if (iorq->sectcnt) { /* more to go! */ 1782 1.1 gwr iorq->lasterror = iorq->errno = iopb->errno = 0; 1783 1.1 gwr iopb->errs = iopb->done = 0; 1784 1.1 gwr iorq->tries = 0; 1785 1.1 gwr iopb->scnt = iorq->sectcnt; 1786 1.69 tsutsui iopb->cyl = 1787 1.69 tsutsui iorq->blockno / iorq->xy->sectpercyl; 1788 1.1 gwr iopb->head = 1789 1.69 tsutsui (iorq->blockno / iorq->xy->nhead) % 1790 1.69 tsutsui iorq->xy->nhead; 1791 1.1 gwr iopb->sect = iorq->blockno % XYFM_BPS; 1792 1.19 gwr addr = dvma_kvtopa(iorq->dbuf, xycsc->bustype); 1793 1.1 gwr iopb->dataa = (addr & 0xffff); 1794 1.1 gwr iopb->datar = ((addr & 0xff0000) >> 16); 1795 1.1 gwr /* will resubit at end */ 1796 1.1 gwr continue; 1797 1.1 gwr } 1798 1.1 gwr } 1799 1.1 gwr /* final cleanup, totally done with this request */ 1800 1.1 gwr 1801 1.1 gwr switch (XY_STATE(iorq->mode)) { 1802 1.1 gwr case XY_SUB_NORM: 1803 1.1 gwr bp = iorq->buf; 1804 1.1 gwr if (errs) { 1805 1.1 gwr bp->b_error = EIO; 1806 1.1 gwr bp->b_resid = iorq->sectcnt * XYFM_BPS; 1807 1.1 gwr } else { 1808 1.1 gwr bp->b_resid = 0; /* done */ 1809 1.1 gwr } 1810 1.1 gwr /* Sun3: map/unmap regardless of B_PHYS */ 1811 1.69 tsutsui dvma_mapout(iorq->dbufbase, iorq->buf->b_bcount); 1812 1.71 yamt (void)bufq_get(iorq->xy->xyq); 1813 1.2 thorpej disk_unbusy(&iorq->xy->sc_dk, 1814 1.43 mrg (bp->b_bcount - bp->b_resid), 1815 1.43 mrg (bp->b_flags & B_READ)); 1816 1.17 gwr iorq->mode = XY_SUB_FREE; 1817 1.1 gwr biodone(bp); 1818 1.1 gwr break; 1819 1.1 gwr case XY_SUB_WAIT: 1820 1.1 gwr iorq->mode = XY_NEWSTATE(iorq->mode, XY_SUB_DONE); 1821 1.1 gwr wakeup(iorq); 1822 1.1 gwr break; 1823 1.1 gwr case XY_SUB_POLL: 1824 1.1 gwr iorq->mode = XY_NEWSTATE(iorq->mode, XY_SUB_DONE); 1825 1.1 gwr break; 1826 1.1 gwr } 1827 1.1 gwr } 1828 1.1 gwr 1829 1.69 tsutsui return XY_ERR_AOK; 1830 1.1 gwr } 1831 1.1 gwr 1832 1.1 gwr /* 1833 1.1 gwr * xyc_perror: print error. 1834 1.1 gwr * - if still_trying is true: we got an error, retried and got a 1835 1.1 gwr * different error. in that case lasterror is the old error, 1836 1.1 gwr * and errno is the new one. 1837 1.1 gwr * - if still_trying is not true, then if we ever had an error it 1838 1.1 gwr * is in lasterror. also, if iorq->errno == 0, then we recovered 1839 1.1 gwr * from that error (otherwise iorq->errno == iorq->lasterror). 1840 1.1 gwr */ 1841 1.83 tsutsui void 1842 1.50 chs xyc_perror(struct xy_iorq *iorq, struct xy_iopb *iopb, int still_trying) 1843 1.1 gwr { 1844 1.69 tsutsui int error = iorq->lasterror; 1845 1.1 gwr 1846 1.69 tsutsui printf("%s", (iorq->xy) ? device_xname(iorq->xy->sc_dev) 1847 1.69 tsutsui : device_xname(iorq->xyc->sc_dev)); 1848 1.1 gwr if (iorq->buf) 1849 1.70 cegger printf("%c: ", 'a' + (char)DISKPART(iorq->buf->b_dev)); 1850 1.1 gwr if (iopb->com == XYCMD_RD || iopb->com == XYCMD_WR) 1851 1.11 christos printf("%s %d/%d/%d: ", 1852 1.69 tsutsui (iopb->com == XYCMD_RD) ? "read" : "write", 1853 1.69 tsutsui iopb->cyl, iopb->head, iopb->sect); 1854 1.11 christos printf("%s", xyc_e2str(error)); 1855 1.1 gwr 1856 1.1 gwr if (still_trying) 1857 1.11 christos printf(" [still trying, new error=%s]", xyc_e2str(iorq->errno)); 1858 1.1 gwr else 1859 1.1 gwr if (iorq->errno == 0) 1860 1.11 christos printf(" [recovered in %d tries]", iorq->tries); 1861 1.1 gwr 1862 1.11 christos printf("\n"); 1863 1.1 gwr } 1864 1.1 gwr 1865 1.1 gwr /* 1866 1.1 gwr * xyc_error: non-fatal error encountered... recover. 1867 1.1 gwr * return AOK if resubmitted, return FAIL if this iopb is done 1868 1.1 gwr */ 1869 1.83 tsutsui int 1870 1.50 chs xyc_error(struct xyc_softc *xycsc, struct xy_iorq *iorq, struct xy_iopb *iopb, 1871 1.50 chs int comm) 1872 1.1 gwr { 1873 1.69 tsutsui int errno = iorq->errno; 1874 1.69 tsutsui int erract = xyc_entoact(errno); 1875 1.69 tsutsui int oldmode, advance, i; 1876 1.1 gwr 1877 1.1 gwr if (erract == XY_ERA_RSET) { /* some errors require a reset */ 1878 1.1 gwr oldmode = iorq->mode; 1879 1.1 gwr iorq->mode = XY_SUB_DONE | (~XY_SUB_MASK & oldmode); 1880 1.1 gwr /* make xyc_start ignore us */ 1881 1.1 gwr xyc_reset(xycsc, 1, XY_RSET_NONE, errno, iorq->xy); 1882 1.1 gwr iorq->mode = oldmode; 1883 1.1 gwr } 1884 1.1 gwr /* check for read/write to a sector in bad144 table if bad: redirect 1885 1.1 gwr * request to bad144 area */ 1886 1.1 gwr 1887 1.1 gwr if ((comm == XYCMD_RD || comm == XYCMD_WR) && 1888 1.1 gwr (iorq->mode & XY_MODE_B144) == 0) { 1889 1.1 gwr advance = iorq->sectcnt - iopb->scnt; 1890 1.1 gwr XYC_ADVANCE(iorq, advance); 1891 1.69 tsutsui if ((i = isbad(&iorq->xy->dkb, 1892 1.69 tsutsui iorq->blockno / iorq->xy->sectpercyl, 1893 1.69 tsutsui (iorq->blockno / iorq->xy->nsect) % iorq->xy->nhead, 1894 1.69 tsutsui iorq->blockno % iorq->xy->nsect)) != -1) { 1895 1.1 gwr iorq->mode |= XY_MODE_B144; /* enter bad144 mode & 1896 1.1 gwr * redirect */ 1897 1.1 gwr iopb->errno = iopb->done = iopb->errs = 0; 1898 1.1 gwr iopb->scnt = 1; 1899 1.1 gwr iopb->cyl = (iorq->xy->ncyl + iorq->xy->acyl) - 2; 1900 1.1 gwr /* second to last acyl */ 1901 1.1 gwr i = iorq->xy->sectpercyl - 1 - i; /* follow bad144 1902 1.1 gwr * standard */ 1903 1.1 gwr iopb->head = i / iorq->xy->nhead; 1904 1.1 gwr iopb->sect = i % iorq->xy->nhead; 1905 1.1 gwr /* will resubmit when we come out of remove_iorq */ 1906 1.69 tsutsui return XY_ERR_AOK; /* recovered! */ 1907 1.1 gwr } 1908 1.1 gwr } 1909 1.1 gwr 1910 1.1 gwr /* 1911 1.1 gwr * it isn't a bad144 sector, must be real error! see if we can retry 1912 1.1 gwr * it? 1913 1.1 gwr */ 1914 1.1 gwr if ((iorq->mode & XY_MODE_VERBO) && iorq->lasterror) 1915 1.1 gwr xyc_perror(iorq, iopb, 1); /* inform of error state 1916 1.1 gwr * change */ 1917 1.1 gwr iorq->lasterror = errno; 1918 1.1 gwr 1919 1.1 gwr if ((erract == XY_ERA_RSET || erract == XY_ERA_HARD) 1920 1.1 gwr && iorq->tries < XYC_MAXTRIES) { /* retry? */ 1921 1.1 gwr iorq->tries++; 1922 1.1 gwr iorq->errno = iopb->errno = iopb->done = iopb->errs = 0; 1923 1.1 gwr /* will resubmit at end of remove_iorq */ 1924 1.69 tsutsui return XY_ERR_AOK; /* recovered! */ 1925 1.1 gwr } 1926 1.1 gwr 1927 1.1 gwr /* failed to recover from this error */ 1928 1.69 tsutsui return XY_ERR_FAIL; 1929 1.1 gwr } 1930 1.1 gwr 1931 1.1 gwr /* 1932 1.1 gwr * xyc_tick: make sure xy is still alive and ticking (err, kicking). 1933 1.1 gwr */ 1934 1.83 tsutsui void 1935 1.50 chs xyc_tick(void *arg) 1936 1.1 gwr { 1937 1.1 gwr struct xyc_softc *xycsc = arg; 1938 1.69 tsutsui int lcv, s, reset = 0; 1939 1.1 gwr 1940 1.1 gwr /* reduce ttl for each request if one goes to zero, reset xyc */ 1941 1.1 gwr s = splbio(); 1942 1.1 gwr for (lcv = 0; lcv < XYC_MAXIOPB; lcv++) { 1943 1.1 gwr if (xycsc->reqs[lcv].mode == 0 || 1944 1.1 gwr XY_STATE(xycsc->reqs[lcv].mode) == XY_SUB_DONE) 1945 1.1 gwr continue; 1946 1.1 gwr xycsc->reqs[lcv].ttl--; 1947 1.1 gwr if (xycsc->reqs[lcv].ttl == 0) 1948 1.1 gwr reset = 1; 1949 1.1 gwr } 1950 1.1 gwr if (reset) { 1951 1.69 tsutsui printf("%s: watchdog timeout\n", device_xname(xycsc->sc_dev)); 1952 1.1 gwr xyc_reset(xycsc, 0, XY_RSET_NONE, XY_ERR_FAIL, NULL); 1953 1.1 gwr } 1954 1.1 gwr splx(s); 1955 1.1 gwr 1956 1.1 gwr /* until next time */ 1957 1.1 gwr 1958 1.27 tsutsui callout_reset(&xycsc->sc_tick_ch, XYC_TICKCNT, xyc_tick, xycsc); 1959 1.1 gwr } 1960 1.1 gwr 1961 1.1 gwr /* 1962 1.1 gwr * xyc_ioctlcmd: this function provides a user level interface to the 1963 1.1 gwr * controller via ioctl. this allows "format" programs to be written 1964 1.1 gwr * in user code, and is also useful for some debugging. we return 1965 1.1 gwr * an error code. called at user priority. 1966 1.1 gwr * 1967 1.1 gwr * XXX missing a few commands (see the 7053 driver for ideas) 1968 1.1 gwr */ 1969 1.83 tsutsui int 1970 1.50 chs xyc_ioctlcmd(struct xy_softc *xy, dev_t dev, struct xd_iocmd *xio) 1971 1.1 gwr { 1972 1.69 tsutsui int s, err, rqno; 1973 1.59 christos void *dvmabuf = NULL; 1974 1.1 gwr struct xyc_softc *xycsc; 1975 1.1 gwr 1976 1.1 gwr /* check sanity of requested command */ 1977 1.1 gwr 1978 1.1 gwr switch (xio->cmd) { 1979 1.1 gwr 1980 1.1 gwr case XYCMD_NOP: /* no op: everything should be zero */ 1981 1.1 gwr if (xio->subfn || xio->dptr || xio->dlen || 1982 1.1 gwr xio->block || xio->sectcnt) 1983 1.69 tsutsui return EINVAL; 1984 1.1 gwr break; 1985 1.1 gwr 1986 1.1 gwr case XYCMD_RD: /* read / write sectors (up to XD_IOCMD_MAXS) */ 1987 1.1 gwr case XYCMD_WR: 1988 1.1 gwr if (xio->subfn || xio->sectcnt > XD_IOCMD_MAXS || 1989 1.1 gwr xio->sectcnt * XYFM_BPS != xio->dlen || xio->dptr == NULL) 1990 1.69 tsutsui return EINVAL; 1991 1.1 gwr break; 1992 1.1 gwr 1993 1.1 gwr case XYCMD_SK: /* seek: doesn't seem useful to export this */ 1994 1.69 tsutsui return EINVAL; 1995 1.1 gwr break; 1996 1.1 gwr 1997 1.1 gwr default: 1998 1.69 tsutsui return EINVAL;/* ??? */ 1999 1.1 gwr } 2000 1.1 gwr 2001 1.1 gwr /* create DVMA buffer for request if needed */ 2002 1.1 gwr 2003 1.1 gwr if (xio->dlen) { 2004 1.1 gwr dvmabuf = dvma_malloc(xio->dlen); 2005 1.1 gwr if (xio->cmd == XYCMD_WR) { 2006 1.17 gwr err = copyin(xio->dptr, dvmabuf, xio->dlen); 2007 1.17 gwr if (err) { 2008 1.1 gwr dvma_free(dvmabuf, xio->dlen); 2009 1.69 tsutsui return err; 2010 1.1 gwr } 2011 1.1 gwr } 2012 1.1 gwr } 2013 1.1 gwr /* do it! */ 2014 1.1 gwr 2015 1.1 gwr err = 0; 2016 1.1 gwr xycsc = xy->parent; 2017 1.1 gwr s = splbio(); 2018 1.1 gwr rqno = xyc_cmd(xycsc, xio->cmd, xio->subfn, xy->xy_drive, xio->block, 2019 1.1 gwr xio->sectcnt, dvmabuf, XY_SUB_WAIT); 2020 1.1 gwr if (rqno == XY_ERR_FAIL) { 2021 1.1 gwr err = EIO; 2022 1.1 gwr goto done; 2023 1.1 gwr } 2024 1.1 gwr xio->errno = xycsc->ciorq->errno; 2025 1.1 gwr xio->tries = xycsc->ciorq->tries; 2026 1.17 gwr XYC_DONE(xycsc, err); 2027 1.1 gwr 2028 1.1 gwr if (xio->cmd == XYCMD_RD) 2029 1.1 gwr err = copyout(dvmabuf, xio->dptr, xio->dlen); 2030 1.1 gwr 2031 1.69 tsutsui done: 2032 1.1 gwr splx(s); 2033 1.1 gwr if (dvmabuf) 2034 1.1 gwr dvma_free(dvmabuf, xio->dlen); 2035 1.69 tsutsui return err; 2036 1.1 gwr } 2037 1.1 gwr 2038 1.1 gwr /* 2039 1.1 gwr * xyc_e2str: convert error code number into an error string 2040 1.1 gwr */ 2041 1.51 tsutsui const char * 2042 1.50 chs xyc_e2str(int no) 2043 1.1 gwr { 2044 1.1 gwr switch (no) { 2045 1.1 gwr case XY_ERR_FAIL: 2046 1.69 tsutsui return "Software fatal error"; 2047 1.1 gwr case XY_ERR_DERR: 2048 1.69 tsutsui return "DOUBLE ERROR"; 2049 1.1 gwr case XY_ERR_AOK: 2050 1.69 tsutsui return "Successful completion"; 2051 1.1 gwr case XY_ERR_IPEN: 2052 1.69 tsutsui return "Interrupt pending"; 2053 1.1 gwr case XY_ERR_BCFL: 2054 1.69 tsutsui return "Busy conflict"; 2055 1.1 gwr case XY_ERR_TIMO: 2056 1.69 tsutsui return "Operation timeout"; 2057 1.1 gwr case XY_ERR_NHDR: 2058 1.69 tsutsui return "Header not found"; 2059 1.1 gwr case XY_ERR_HARD: 2060 1.69 tsutsui return "Hard ECC error"; 2061 1.1 gwr case XY_ERR_ICYL: 2062 1.69 tsutsui return "Illegal cylinder address"; 2063 1.1 gwr case XY_ERR_ISEC: 2064 1.69 tsutsui return "Illegal sector address"; 2065 1.1 gwr case XY_ERR_SMAL: 2066 1.69 tsutsui return "Last sector too small"; 2067 1.1 gwr case XY_ERR_SACK: 2068 1.69 tsutsui return "Slave ACK error (non-existent memory)"; 2069 1.1 gwr case XY_ERR_CHER: 2070 1.69 tsutsui return "Cylinder and head/header error"; 2071 1.1 gwr case XY_ERR_SRTR: 2072 1.69 tsutsui return "Auto-seek retry successful"; 2073 1.1 gwr case XY_ERR_WPRO: 2074 1.69 tsutsui return "Write-protect error"; 2075 1.1 gwr case XY_ERR_UIMP: 2076 1.69 tsutsui return "Unimplemented command"; 2077 1.1 gwr case XY_ERR_DNRY: 2078 1.69 tsutsui return "Drive not ready"; 2079 1.1 gwr case XY_ERR_SZER: 2080 1.69 tsutsui return "Sector count zero"; 2081 1.1 gwr case XY_ERR_DFLT: 2082 1.69 tsutsui return "Drive faulted"; 2083 1.1 gwr case XY_ERR_ISSZ: 2084 1.69 tsutsui return "Illegal sector size"; 2085 1.1 gwr case XY_ERR_SLTA: 2086 1.69 tsutsui return "Self test A"; 2087 1.1 gwr case XY_ERR_SLTB: 2088 1.69 tsutsui return "Self test B"; 2089 1.1 gwr case XY_ERR_SLTC: 2090 1.69 tsutsui return "Self test C"; 2091 1.1 gwr case XY_ERR_SOFT: 2092 1.69 tsutsui return "Soft ECC error"; 2093 1.1 gwr case XY_ERR_SFOK: 2094 1.69 tsutsui return "Soft ECC error recovered"; 2095 1.1 gwr case XY_ERR_IHED: 2096 1.69 tsutsui return "Illegal head"; 2097 1.1 gwr case XY_ERR_DSEQ: 2098 1.69 tsutsui return "Disk sequencer error"; 2099 1.1 gwr case XY_ERR_SEEK: 2100 1.69 tsutsui return "Seek error"; 2101 1.1 gwr default: 2102 1.69 tsutsui return "Unknown error"; 2103 1.1 gwr } 2104 1.1 gwr } 2105 1.1 gwr 2106 1.83 tsutsui int 2107 1.50 chs xyc_entoact(int errno) 2108 1.1 gwr { 2109 1.69 tsutsui 2110 1.50 chs switch (errno) { 2111 1.69 tsutsui case XY_ERR_FAIL: 2112 1.69 tsutsui case XY_ERR_DERR: 2113 1.69 tsutsui case XY_ERR_IPEN: 2114 1.69 tsutsui case XY_ERR_BCFL: 2115 1.69 tsutsui case XY_ERR_ICYL: 2116 1.69 tsutsui case XY_ERR_ISEC: 2117 1.69 tsutsui case XY_ERR_UIMP: 2118 1.69 tsutsui case XY_ERR_SZER: 2119 1.69 tsutsui case XY_ERR_ISSZ: 2120 1.69 tsutsui case XY_ERR_SLTA: 2121 1.69 tsutsui case XY_ERR_SLTB: 2122 1.69 tsutsui case XY_ERR_SLTC: 2123 1.69 tsutsui case XY_ERR_IHED: 2124 1.69 tsutsui case XY_ERR_SACK: 2125 1.69 tsutsui case XY_ERR_SMAL: 2126 1.69 tsutsui return XY_ERA_PROG; /* program error ! */ 2127 1.1 gwr 2128 1.69 tsutsui case XY_ERR_TIMO: 2129 1.69 tsutsui case XY_ERR_NHDR: 2130 1.69 tsutsui case XY_ERR_HARD: 2131 1.69 tsutsui case XY_ERR_DNRY: 2132 1.69 tsutsui case XY_ERR_CHER: 2133 1.69 tsutsui case XY_ERR_SEEK: 2134 1.50 chs case XY_ERR_SOFT: 2135 1.69 tsutsui return XY_ERA_HARD; /* hard error, retry */ 2136 1.1 gwr 2137 1.69 tsutsui case XY_ERR_DFLT: 2138 1.69 tsutsui case XY_ERR_DSEQ: 2139 1.69 tsutsui return XY_ERA_RSET; /* hard error reset */ 2140 1.1 gwr 2141 1.69 tsutsui case XY_ERR_SRTR: 2142 1.69 tsutsui case XY_ERR_SFOK: 2143 1.69 tsutsui case XY_ERR_AOK: 2144 1.69 tsutsui return XY_ERA_SOFT; /* an FYI error */ 2145 1.1 gwr 2146 1.50 chs case XY_ERR_WPRO: 2147 1.69 tsutsui return XY_ERA_WPRO; /* write protect */ 2148 1.50 chs } 2149 1.1 gwr 2150 1.69 tsutsui return XY_ERA_PROG; /* ??? */ 2151 1.1 gwr } 2152