fdc.c 8.1 KB

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