1 /* $OpenBSD: fdc.c,v 1.14 2001/03/06 13:55:02 ho Exp $ */ 2 /* $NetBSD: fd.c,v 1.90 1996/05/12 23:12:03 mycroft Exp $ */ 3 4 /*- 5 * Copyright (c) 1993, 1994, 1995 Charles Hannum. 6 * Copyright (c) 1990 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Don Ahn. 11 * 12 * Portions Copyright (c) 1993, 1994 by 13 * jc@irbs.UUCP (John Capo) 14 * vak@zebub.msk.su (Serge Vakulenko) 15 * ache@astral.msk.su (Andrew A. Chernov) 16 * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 3. All advertising materials mentioning features or use of this software 27 * must display the following acknowledgement: 28 * This product includes software developed by the University of 29 * California, Berkeley and its contributors. 30 * 4. Neither the name of the University nor the names of its contributors 31 * may be used to endorse or promote products derived from this software 32 * without specific prior written permission. 33 * 34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 * 46 * @(#)fd.c 7.4 (Berkeley) 5/25/91 47 */ 48 49 #include <sys/param.h> 50 #include <sys/systm.h> 51 #include <sys/kernel.h> 52 #include <sys/file.h> 53 #include <sys/ioctl.h> 54 #include <sys/device.h> 55 #include <sys/disklabel.h> 56 #include <sys/dkstat.h> 57 #include <sys/disk.h> 58 #include <sys/buf.h> 59 #include <sys/malloc.h> 60 #include <sys/uio.h> 61 #include <sys/mtio.h> 62 #include <sys/syslog.h> 63 #include <sys/queue.h> 64 #include <sys/timeout.h> 65 66 #include <machine/cpu.h> 67 #include <machine/bus.h> 68 #include <machine/conf.h> 69 #include <machine/intr.h> 70 #include <machine/ioctl_fd.h> 71 72 #include <dev/isa/isavar.h> 73 #include <dev/isa/isadmavar.h> 74 #include <dev/isa/fdreg.h> 75 76 #if defined(i386) 77 #include <dev/ic/mc146818reg.h> /* for NVRAM access */ 78 #include <i386/isa/nvram.h> 79 #endif 80 81 #include <dev/isa/fdlink.h> 82 83 #include "fd.h" 84 85 /* controller driver configuration */ 86 int fdcprobe __P((struct device *, void *, void *)); 87 void fdcattach __P((struct device *, struct device *, void *)); 88 89 struct cfattach fdc_ca = { 90 sizeof(struct fdc_softc), fdcprobe, fdcattach 91 }; 92 93 struct cfdriver fdc_cd = { 94 NULL, "fdc", DV_DULL 95 }; 96 97 int fddprint __P((void *, const char *)); 98 int fdcintr __P((void *)); 99 100 int 101 fdcprobe(parent, match, aux) 102 struct device *parent; 103 void *match, *aux; 104 { 105 register struct isa_attach_args *ia = aux; 106 bus_space_tag_t iot; 107 bus_space_handle_t ioh; 108 bus_space_handle_t ioh_ctl; 109 int rv; 110 111 iot = ia->ia_iot; 112 rv = 0; 113 114 /* Map the i/o space. */ 115 if (bus_space_map(iot, ia->ia_iobase, FDC_NPORT, 0, &ioh)) 116 return 0; 117 if (bus_space_map(iot, ia->ia_iobase + FDCTL_OFFSET, 118 FDCTL_NPORT, 0, &ioh_ctl)) 119 return 0; 120 121 /* reset */ 122 bus_space_write_1(iot, ioh, fdout, 0); 123 delay(100); 124 bus_space_write_1(iot, ioh, fdout, FDO_FRST); 125 126 /* see if it can handle a command */ 127 if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0) 128 goto out; 129 out_fdc(iot, ioh, 0xdf); 130 out_fdc(iot, ioh, 2); 131 132 rv = 1; 133 ia->ia_iosize = FDC_NPORT; 134 ia->ia_msize = 0; 135 136 out: 137 bus_space_unmap(iot, ioh, FDC_NPORT); 138 bus_space_unmap(iot, ioh_ctl, FDCTL_NPORT); 139 return rv; 140 } 141 142 void 143 fdcattach(parent, self, aux) 144 struct device *parent, *self; 145 void *aux; 146 { 147 struct fdc_softc *fdc = (void *)self; 148 bus_space_tag_t iot; 149 bus_space_handle_t ioh; 150 bus_space_handle_t ioh_ctl; 151 struct isa_attach_args *ia = aux; 152 struct fdc_attach_args fa; 153 int type; 154 155 iot = ia->ia_iot; 156 157 /* Re-map the I/O space. */ 158 if (bus_space_map(iot, ia->ia_iobase, FDC_NPORT, 0, &ioh) || 159 bus_space_map(iot, ia->ia_iobase + FDCTL_OFFSET, 160 FDCTL_NPORT, 0, &ioh_ctl)) 161 panic("fdcattach: couldn't map I/O ports"); 162 163 fdc->sc_iot = iot; 164 fdc->sc_ioh = ioh; 165 fdc->sc_ioh_ctl = ioh_ctl; 166 167 fdc->sc_drq = ia->ia_drq; 168 fdc->sc_state = DEVIDLE; 169 TAILQ_INIT(&fdc->sc_link.fdlink.sc_drives); /* XXX */ 170 171 printf("\n"); 172 173 fdc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 174 IPL_BIO, fdcintr, fdc, fdc->sc_dev.dv_xname); 175 176 #if defined(i386) 177 /* 178 * The NVRAM info only tells us about the first two disks on the 179 * `primary' floppy controller. 180 */ 181 if (fdc->sc_dev.dv_unit == 0) 182 type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */ 183 else 184 #endif 185 type = -1; 186 187 timeout_set(&fdc->fdcpseudointr_to, fdcpseudointr, fdc); 188 189 /* physical limit: four drives per controller. */ 190 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 191 fa.fa_flags = 0; 192 fa.fa_type = 0; 193 #if NFD > 0 194 if (type >= 0 && fa.fa_drive < 2) 195 fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname, 196 type, fa.fa_drive); 197 else 198 #endif 199 fa.fa_deftype = NULL; /* unknown */ 200 (void)config_found(self, (void *)&fa, fddprint); 201 } 202 } 203 204 /* 205 * Print the location of a disk/tape drive (called just before attaching the 206 * the drive). If `fdc' is not NULL, the drive was found but was not 207 * in the system config file; print the drive name as well. 208 * Return QUIET (config_find ignores this if the device was configured) to 209 * avoid printing `fdN not configured' messages. 210 */ 211 int 212 fddprint(aux, fdc) 213 void *aux; 214 const char *fdc; 215 { 216 register struct fdc_attach_args *fa = aux; 217 218 if (!fdc) 219 printf(" drive %d", fa->fa_drive); 220 return QUIET; 221 } 222 223 int 224 fdcresult(fdc) 225 struct fdc_softc *fdc; 226 { 227 bus_space_tag_t iot = fdc->sc_iot; 228 bus_space_handle_t ioh = fdc->sc_ioh; 229 u_char i; 230 int j = 100000, n = 0; 231 232 for (; j; j--) { 233 i = bus_space_read_1(iot, ioh, fdsts) & 234 (NE7_DIO | NE7_RQM | NE7_CB); 235 if (i == NE7_RQM) 236 return n; 237 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 238 if (n >= sizeof(fdc->sc_status)) { 239 log(LOG_ERR, "fdcresult: overrun\n"); 240 return -1; 241 } 242 fdc->sc_status[n++] = 243 bus_space_read_1(iot, ioh, fddata); 244 } 245 delay(10); 246 } 247 return -1; 248 } 249 250 int 251 out_fdc(iot, ioh, x) 252 bus_space_tag_t iot; 253 bus_space_handle_t ioh; 254 u_char x; 255 { 256 int i = 100000; 257 258 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0); 259 if (i <= 0) 260 return -1; 261 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0); 262 if (i <= 0) 263 return -1; 264 bus_space_write_1(iot, ioh, fddata, x); 265 return 0; 266 } 267 268 void 269 fdcstart(fdc) 270 struct fdc_softc *fdc; 271 { 272 273 #ifdef DIAGNOSTIC 274 /* only got here if controller's drive queue was inactive; should 275 be in idle state */ 276 if (fdc->sc_state != DEVIDLE) { 277 printf("fdcstart: not idle\n"); 278 return; 279 } 280 #endif 281 (void) fdcintr(fdc); 282 } 283 284 void 285 fdcstatus(dv, n, s) 286 struct device *dv; 287 int n; 288 char *s; 289 { 290 struct fdc_softc *fdc = (void *)dv->dv_parent; 291 292 if (n == 0) { 293 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 294 (void) fdcresult(fdc); 295 n = 2; 296 } 297 298 printf("%s: %s", dv->dv_xname, s); 299 300 switch (n) { 301 case 0: 302 printf("\n"); 303 break; 304 case 2: 305 printf(" (st0 %b cyl %d)\n", 306 fdc->sc_status[0], NE7_ST0BITS, 307 fdc->sc_status[1]); 308 break; 309 case 7: 310 printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n", 311 fdc->sc_status[0], NE7_ST0BITS, 312 fdc->sc_status[1], NE7_ST1BITS, 313 fdc->sc_status[2], NE7_ST2BITS, 314 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 315 break; 316 #ifdef DIAGNOSTIC 317 default: 318 printf("\nfdcstatus: weird size"); 319 break; 320 #endif 321 } 322 } 323 324 void 325 fdcpseudointr(arg) 326 void *arg; 327 { 328 int s; 329 330 /* Just ensure it has the right spl. */ 331 s = splbio(); 332 (void) fdcintr(arg); 333 splx(s); 334 } 335 336 int 337 fdcintr(arg) 338 void *arg; 339 { 340 #if NFD > 0 341 struct fdc_softc *fdc = arg; 342 extern int fdintr __P((struct fdc_softc *)); 343 344 /* Will switch on device type, shortly. */ 345 return (fdintr(fdc)); 346 #else 347 printf("fdcintr: got interrupt, but no devices!\n"); 348 return (1); 349 #endif 350 } 351