devfloppy.c 20 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "../port/error.h"
  8. #include "floppy.h"
  9. /* Intel 82077A (8272A compatible) floppy controller */
  10. /* This module expects the following functions to be defined
  11. * elsewhere:
  12. *
  13. * inb()
  14. * outb()
  15. * floppyexec()
  16. * floppyeject()
  17. * floppysetup0()
  18. * floppysetup1()
  19. * dmainit()
  20. * dmasetup()
  21. * dmaend()
  22. *
  23. * On DMA systems, floppyexec() should be an empty function;
  24. * on non-DMA systems, dmaend() should be an empty function;
  25. * dmasetup() may enforce maximum transfer sizes.
  26. */
  27. enum {
  28. /* file types */
  29. Qdir= 0,
  30. Qdata= (1<<2),
  31. Qctl= (2<<2),
  32. Qmask= (3<<2),
  33. DMAchan= 2, /* floppy dma channel */
  34. };
  35. #define DPRINT if(floppydebug)print
  36. int floppydebug = 0;
  37. /*
  38. * types of drive (from PC equipment byte)
  39. */
  40. enum
  41. {
  42. Tnone= 0,
  43. T360kb= 1,
  44. T1200kb= 2,
  45. T720kb= 3,
  46. T1440kb= 4,
  47. };
  48. FType floppytype[] =
  49. {
  50. { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
  51. { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
  52. { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
  53. { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
  54. { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, },
  55. { "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, },
  56. { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
  57. };
  58. /*
  59. * bytes per sector encoding for the controller.
  60. * - index for b2c is is (bytes per sector/128).
  61. * - index for c2b is code from b2c
  62. */
  63. static int b2c[] =
  64. {
  65. [1] 0,
  66. [2] 1,
  67. [4] 2,
  68. [8] 3,
  69. };
  70. static int c2b[] =
  71. {
  72. 128,
  73. 256,
  74. 512,
  75. 1024,
  76. };
  77. FController fl;
  78. #define MOTORBIT(i) (1<<((i)+4))
  79. /*
  80. * predeclared
  81. */
  82. static int cmddone(void*);
  83. static void floppyformat(FDrive*, Cmdbuf*);
  84. static void floppykproc(void*);
  85. static void floppypos(FDrive*,long);
  86. static int floppyrecal(FDrive*);
  87. static int floppyresult(void);
  88. static void floppyrevive(void);
  89. static long floppyseek(FDrive*, long);
  90. static int floppysense(void);
  91. static void floppywait(int);
  92. static long floppyxfer(FDrive*, int, void*, long, long);
  93. Dirtab floppydir[]={
  94. ".", {Qdir, 0, QTDIR}, 0, 0550,
  95. "fd0disk", {Qdata + 0}, 0, 0660,
  96. "fd0ctl", {Qctl + 0}, 0, 0660,
  97. "fd1disk", {Qdata + 1}, 0, 0660,
  98. "fd1ctl", {Qctl + 1}, 0, 0660,
  99. "fd2disk", {Qdata + 2}, 0, 0660,
  100. "fd2ctl", {Qctl + 2}, 0, 0660,
  101. "fd3disk", {Qdata + 3}, 0, 0660,
  102. "fd3ctl", {Qctl + 3}, 0, 0660,
  103. };
  104. #define NFDIR 2 /* directory entries/drive */
  105. enum
  106. {
  107. CMdebug,
  108. CMnodebug,
  109. CMeject,
  110. CMformat,
  111. CMreset,
  112. };
  113. static Cmdtab floppyctlmsg[] =
  114. {
  115. CMdebug, "debug", 1,
  116. CMnodebug, "nodebug", 1,
  117. CMeject, "eject", 1,
  118. CMformat, "format", 0,
  119. CMreset, "reset", 1,
  120. };
  121. static void
  122. fldump(void)
  123. {
  124. DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb),
  125. inb(Pdor), inb(Pmsr), inb(Pdir));
  126. }
  127. /*
  128. * set floppy drive to its default type
  129. */
  130. static void
  131. floppysetdef(FDrive *dp)
  132. {
  133. FType *t;
  134. for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++)
  135. if(dp->dt == t->dt){
  136. dp->t = t;
  137. floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
  138. break;
  139. }
  140. }
  141. static void
  142. floppyreset(void)
  143. {
  144. FDrive *dp;
  145. FType *t;
  146. ulong maxtsize;
  147. floppysetup0(&fl);
  148. if(fl.ndrive == 0)
  149. return;
  150. /*
  151. * init dependent parameters
  152. */
  153. maxtsize = 0;
  154. for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
  155. t->cap = t->bytes * t->heads * t->sectors * t->tracks;
  156. t->bcode = b2c[t->bytes/128];
  157. t->tsize = t->bytes * t->sectors;
  158. if(maxtsize < t->tsize)
  159. maxtsize = t->tsize;
  160. }
  161. /*
  162. * Should check if this fails. Can do so
  163. * if there is no space <= 16MB for the DMA
  164. * bounce buffer.
  165. */
  166. dmainit(DMAchan, maxtsize);
  167. /*
  168. * allocate the drive storage
  169. */
  170. fl.d = xalloc(fl.ndrive*sizeof(FDrive));
  171. fl.selected = fl.d;
  172. /*
  173. * stop the motors
  174. */
  175. fl.motor = 0;
  176. delay(10);
  177. outb(Pdor, fl.motor | Fintena | Fena);
  178. delay(10);
  179. /*
  180. * init drives
  181. */
  182. for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
  183. dp->dev = dp - fl.d;
  184. dp->dt = T1440kb;
  185. floppysetdef(dp);
  186. dp->cyl = -1; /* because we don't know */
  187. dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024);
  188. dp->ccyl = -1;
  189. dp->vers = 0;
  190. }
  191. /*
  192. * first operation will recalibrate
  193. */
  194. fl.confused = 1;
  195. floppysetup1(&fl);
  196. }
  197. static Chan*
  198. floppyattach(char *spec)
  199. {
  200. static int kstarted;
  201. if(fl.ndrive == 0)
  202. error(Enodev);
  203. if(kstarted == 0){
  204. /*
  205. * watchdog to turn off the motors
  206. */
  207. kstarted = 1;
  208. kproc("floppy", floppykproc, 0);
  209. }
  210. return devattach('f', spec);
  211. }
  212. static Walkqid*
  213. floppywalk(Chan *c, Chan *nc, char **name, int nname)
  214. {
  215. return devwalk(c, nc, name, nname, floppydir, 1+fl.ndrive*NFDIR, devgen);
  216. }
  217. static int
  218. floppystat(Chan *c, uchar *dp, int n)
  219. {
  220. return devstat(c, dp, n, floppydir, 1+fl.ndrive*NFDIR, devgen);
  221. }
  222. static Chan*
  223. floppyopen(Chan *c, int omode)
  224. {
  225. return devopen(c, omode, floppydir, 1+fl.ndrive*NFDIR, devgen);
  226. }
  227. static void
  228. floppyclose(Chan *)
  229. {
  230. }
  231. static void
  232. islegal(ulong offset, long n, FDrive *dp)
  233. {
  234. if(offset % dp->t->bytes)
  235. error(Ebadarg);
  236. if(n % dp->t->bytes)
  237. error(Ebadarg);
  238. }
  239. /*
  240. * check if the floppy has been replaced under foot. cause
  241. * an error if it has.
  242. *
  243. * a seek and a read clears the condition. this was determined
  244. * experimentally, there has to be a better way.
  245. *
  246. * if the read fails, cycle through the possible floppy
  247. * density till one works or we've cycled through all
  248. * possibilities for this drive.
  249. */
  250. static void
  251. changed(Chan *c, FDrive *dp)
  252. {
  253. ulong old;
  254. FType *start;
  255. /*
  256. * if floppy has changed or first time through
  257. */
  258. if((inb(Pdir)&Fchange) || dp->vers == 0){
  259. DPRINT("changed\n");
  260. fldump();
  261. dp->vers++;
  262. start = dp->t;
  263. dp->maxtries = 3; /* limit it when we're probing */
  264. /* floppyon will fail if there's a controller but no drive */
  265. dp->confused = 1; /* make floppyon recal */
  266. if(floppyon(dp) < 0)
  267. error(Eio);
  268. /* seek to the first track */
  269. floppyseek(dp, dp->t->heads*dp->t->tsize);
  270. while(waserror()){
  271. /*
  272. * if first attempt doesn't reset changed bit, there's
  273. * no floppy there
  274. */
  275. if(inb(Pdir)&Fchange)
  276. nexterror();
  277. while(++dp->t){
  278. if(dp->t == &floppytype[nelem(floppytype)])
  279. dp->t = floppytype;
  280. if(dp->dt == dp->t->dt)
  281. break;
  282. }
  283. floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
  284. /* floppyon will fail if there's a controller but no drive */
  285. if(floppyon(dp) < 0)
  286. error(Eio);
  287. DPRINT("changed: trying %s\n", dp->t->name);
  288. fldump();
  289. if(dp->t == start)
  290. nexterror();
  291. }
  292. /* if the read succeeds, we've got the density right */
  293. floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize);
  294. poperror();
  295. dp->maxtries = 20;
  296. }
  297. old = c->qid.vers;
  298. c->qid.vers = dp->vers;
  299. if(old && old != dp->vers)
  300. error(Eio);
  301. }
  302. static int
  303. readtrack(FDrive *dp, int cyl, int head)
  304. {
  305. int i, nn, sofar;
  306. ulong pos;
  307. nn = dp->t->tsize;
  308. if(dp->ccyl==cyl && dp->chead==head)
  309. return nn;
  310. pos = (cyl*dp->t->heads+head) * nn;
  311. for(sofar = 0; sofar < nn; sofar += i){
  312. dp->ccyl = -1;
  313. i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar);
  314. if(i <= 0)
  315. return -1;
  316. }
  317. dp->ccyl = cyl;
  318. dp->chead = head;
  319. return nn;
  320. }
  321. static long
  322. floppyread(Chan *c, void *a, long n, vlong off)
  323. {
  324. FDrive *dp;
  325. long rv;
  326. int sec, head, cyl;
  327. long len;
  328. uchar *aa;
  329. ulong offset = off;
  330. if(c->qid.type & QTDIR)
  331. return devdirread(c, a, n, floppydir, 1+fl.ndrive*NFDIR, devgen);
  332. rv = 0;
  333. dp = &fl.d[c->qid.path & ~Qmask];
  334. switch ((int)(c->qid.path & Qmask)) {
  335. case Qdata:
  336. islegal(offset, n, dp);
  337. aa = a;
  338. qlock(&fl);
  339. if(waserror()){
  340. qunlock(&fl);
  341. nexterror();
  342. }
  343. floppyon(dp);
  344. changed(c, dp);
  345. for(rv = 0; rv < n; rv += len){
  346. /*
  347. * all xfers come out of the track cache
  348. */
  349. dp->len = n - rv;
  350. floppypos(dp, offset+rv);
  351. cyl = dp->tcyl;
  352. head = dp->thead;
  353. len = dp->len;
  354. sec = dp->tsec;
  355. if(readtrack(dp, cyl, head) < 0)
  356. break;
  357. memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len);
  358. }
  359. qunlock(&fl);
  360. poperror();
  361. break;
  362. case Qctl:
  363. return readstr(offset, a, n, dp->t->name);
  364. default:
  365. panic("floppyread: bad qid");
  366. }
  367. return rv;
  368. }
  369. static long
  370. floppywrite(Chan *c, void *a, long n, vlong off)
  371. {
  372. FDrive *dp;
  373. long rv, i;
  374. char *aa = a;
  375. Cmdbuf *cb;
  376. Cmdtab *ct;
  377. ulong offset = off;
  378. rv = 0;
  379. dp = &fl.d[c->qid.path & ~Qmask];
  380. switch ((int)(c->qid.path & Qmask)) {
  381. case Qdata:
  382. islegal(offset, n, dp);
  383. qlock(&fl);
  384. if(waserror()){
  385. qunlock(&fl);
  386. nexterror();
  387. }
  388. floppyon(dp);
  389. changed(c, dp);
  390. for(rv = 0; rv < n; rv += i){
  391. floppypos(dp, offset+rv);
  392. if(dp->tcyl == dp->ccyl)
  393. dp->ccyl = -1;
  394. i = floppyxfer(dp, Fwrite, aa+rv, offset+rv, n-rv);
  395. if(i < 0)
  396. break;
  397. if(i == 0)
  398. error(Eio);
  399. }
  400. qunlock(&fl);
  401. poperror();
  402. break;
  403. case Qctl:
  404. rv = n;
  405. cb = parsecmd(a, n);
  406. if(waserror()){
  407. free(cb);
  408. nexterror();
  409. }
  410. qlock(&fl);
  411. if(waserror()){
  412. qunlock(&fl);
  413. nexterror();
  414. }
  415. ct = lookupcmd(cb, floppyctlmsg, nelem(floppyctlmsg));
  416. switch(ct->index){
  417. case CMeject:
  418. floppyeject(dp);
  419. break;
  420. case CMformat:
  421. floppyformat(dp, cb);
  422. break;
  423. case CMreset:
  424. fl.confused = 1;
  425. floppyon(dp);
  426. break;
  427. case CMdebug:
  428. floppydebug = 1;
  429. break;
  430. case CMnodebug:
  431. floppydebug = 0;
  432. break;
  433. }
  434. poperror();
  435. qunlock(&fl);
  436. poperror();
  437. free(cb);
  438. break;
  439. default:
  440. panic("floppywrite: bad qid");
  441. }
  442. return rv;
  443. }
  444. static void
  445. floppykproc(void *)
  446. {
  447. FDrive *dp;
  448. while(waserror())
  449. ;
  450. for(;;){
  451. for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
  452. if((fl.motor&MOTORBIT(dp->dev))
  453. && TK2SEC(m->ticks - dp->lasttouched) > 5
  454. && canqlock(&fl)){
  455. if(TK2SEC(m->ticks - dp->lasttouched) > 5)
  456. floppyoff(dp);
  457. qunlock(&fl);
  458. }
  459. }
  460. tsleep(&up->sleep, return0, 0, 1000);
  461. }
  462. }
  463. /*
  464. * start a floppy drive's motor.
  465. */
  466. static int
  467. floppyon(FDrive *dp)
  468. {
  469. int alreadyon;
  470. int tries;
  471. if(fl.confused)
  472. floppyrevive();
  473. /* start motor and select drive */
  474. alreadyon = fl.motor & MOTORBIT(dp->dev);
  475. fl.motor |= MOTORBIT(dp->dev);
  476. outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
  477. if(!alreadyon){
  478. /* wait for drive to spin up */
  479. tsleep(&up->sleep, return0, 0, 750);
  480. /* clear any pending interrupts */
  481. floppysense();
  482. }
  483. /* set transfer rate */
  484. if(fl.rate != dp->t->rate){
  485. fl.rate = dp->t->rate;
  486. outb(Pdsr, fl.rate);
  487. }
  488. /* get drive to a known cylinder */
  489. if(dp->confused)
  490. for(tries = 0; tries < 4; tries++)
  491. if(floppyrecal(dp) >= 0)
  492. break;
  493. dp->lasttouched = m->ticks;
  494. fl.selected = dp;
  495. /* return -1 if this didn't work */
  496. if(dp->confused)
  497. return -1;
  498. return 0;
  499. }
  500. /*
  501. * stop the floppy if it hasn't been used in 5 seconds
  502. */
  503. static void
  504. floppyoff(FDrive *dp)
  505. {
  506. fl.motor &= ~MOTORBIT(dp->dev);
  507. outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
  508. }
  509. /*
  510. * send a command to the floppy
  511. */
  512. static int
  513. floppycmd(void)
  514. {
  515. int i;
  516. int tries;
  517. fl.nstat = 0;
  518. for(i = 0; i < fl.ncmd; i++){
  519. for(tries = 0; ; tries++){
  520. if((inb(Pmsr)&(Ffrom|Fready)) == Fready)
  521. break;
  522. if(tries > 1000){
  523. DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i);
  524. fldump();
  525. /* empty fifo, might have been a bad command */
  526. floppyresult();
  527. return -1;
  528. }
  529. microdelay(8); /* for machine independence */
  530. }
  531. outb(Pfdata, fl.cmd[i]);
  532. }
  533. return 0;
  534. }
  535. /*
  536. * get a command result from the floppy
  537. *
  538. * when the controller goes ready waiting for a command
  539. * (instead of sending results), we're done
  540. *
  541. */
  542. static int
  543. floppyresult(void)
  544. {
  545. int i, s;
  546. int tries;
  547. /* get the result of the operation */
  548. for(i = 0; i < sizeof(fl.stat); i++){
  549. /* wait for status byte */
  550. for(tries = 0; ; tries++){
  551. s = inb(Pmsr)&(Ffrom|Fready);
  552. if(s == Fready){
  553. fl.nstat = i;
  554. return fl.nstat;
  555. }
  556. if(s == (Ffrom|Fready))
  557. break;
  558. if(tries > 1000){
  559. DPRINT("floppyresult: %d stats\n", i);
  560. fldump();
  561. fl.confused = 1;
  562. return -1;
  563. }
  564. microdelay(8); /* for machine independence */
  565. }
  566. fl.stat[i] = inb(Pfdata);
  567. }
  568. fl.nstat = sizeof(fl.stat);
  569. return fl.nstat;
  570. }
  571. /*
  572. * calculate physical address of a logical byte offset into the disk
  573. *
  574. * truncate dp->length if it crosses a track boundary
  575. */
  576. static void
  577. floppypos(FDrive *dp, long off)
  578. {
  579. int lsec;
  580. int ltrack;
  581. int end;
  582. lsec = off/dp->t->bytes;
  583. ltrack = lsec/dp->t->sectors;
  584. dp->tcyl = ltrack/dp->t->heads;
  585. dp->tsec = (lsec % dp->t->sectors) + 1;
  586. dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
  587. /*
  588. * can't read across track boundaries.
  589. * if so, decrement the bytes to be read.
  590. */
  591. end = (ltrack+1)*dp->t->sectors*dp->t->bytes;
  592. if(off+dp->len > end)
  593. dp->len = end - off;
  594. }
  595. /*
  596. * get the interrupt cause from the floppy.
  597. */
  598. static int
  599. floppysense(void)
  600. {
  601. fl.ncmd = 0;
  602. fl.cmd[fl.ncmd++] = Fsense;
  603. if(floppycmd() < 0)
  604. return -1;
  605. if(floppyresult() < 2){
  606. DPRINT("can't read sense response\n");
  607. fldump();
  608. fl.confused = 1;
  609. return -1;
  610. }
  611. return 0;
  612. }
  613. static int
  614. cmddone(void *)
  615. {
  616. return fl.ncmd == 0;
  617. }
  618. /*
  619. * Wait for a floppy interrupt. If none occurs in 5 seconds, we
  620. * may have missed one. This only happens on some portables which
  621. * do power management behind our backs. Call the interrupt
  622. * routine to try to clear any conditions.
  623. */
  624. static void
  625. floppywait(int slow)
  626. {
  627. tsleep(&fl.r, cmddone, 0, slow ? 5000 : 1000);
  628. if(!cmddone(0)){
  629. floppyintr(0);
  630. fl.confused = 1;
  631. }
  632. }
  633. /*
  634. * we've lost the floppy position, go to cylinder 0.
  635. */
  636. static int
  637. floppyrecal(FDrive *dp)
  638. {
  639. dp->ccyl = -1;
  640. dp->cyl = -1;
  641. fl.ncmd = 0;
  642. fl.cmd[fl.ncmd++] = Frecal;
  643. fl.cmd[fl.ncmd++] = dp->dev;
  644. if(floppycmd() < 0)
  645. return -1;
  646. floppywait(1);
  647. if(fl.nstat < 2){
  648. DPRINT("recalibrate: confused %ux\n", inb(Pmsr));
  649. fl.confused = 1;
  650. return -1;
  651. }
  652. if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
  653. DPRINT("recalibrate: failed\n");
  654. dp->confused = 1;
  655. return -1;
  656. }
  657. dp->cyl = fl.stat[1];
  658. if(dp->cyl != 0){
  659. DPRINT("recalibrate: wrong cylinder %d\n", dp->cyl);
  660. dp->cyl = -1;
  661. dp->confused = 1;
  662. return -1;
  663. }
  664. dp->confused = 0;
  665. return 0;
  666. }
  667. /*
  668. * if the controller or a specific drive is in a confused state,
  669. * reset it and get back to a known state
  670. */
  671. static void
  672. floppyrevive(void)
  673. {
  674. FDrive *dp;
  675. /*
  676. * reset the controller if it's confused
  677. */
  678. if(fl.confused){
  679. DPRINT("floppyrevive in\n");
  680. fldump();
  681. /* reset controller and turn all motors off */
  682. splhi();
  683. fl.ncmd = 1;
  684. fl.cmd[0] = 0;
  685. outb(Pdor, 0);
  686. delay(10);
  687. outb(Pdor, Fintena|Fena);
  688. delay(10);
  689. spllo();
  690. fl.motor = 0;
  691. fl.confused = 0;
  692. floppywait(0);
  693. /* mark all drives in an unknown state */
  694. for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++)
  695. dp->confused = 1;
  696. /* set rate to a known value */
  697. outb(Pdsr, 0);
  698. fl.rate = 0;
  699. DPRINT("floppyrevive out\n");
  700. fldump();
  701. }
  702. }
  703. /*
  704. * seek to the target cylinder
  705. *
  706. * interrupt, no results
  707. */
  708. static long
  709. floppyseek(FDrive *dp, long off)
  710. {
  711. floppypos(dp, off);
  712. if(dp->cyl == dp->tcyl)
  713. return dp->tcyl;
  714. dp->cyl = -1;
  715. fl.ncmd = 0;
  716. fl.cmd[fl.ncmd++] = Fseek;
  717. fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
  718. fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps;
  719. if(floppycmd() < 0)
  720. return -1;
  721. floppywait(1);
  722. if(fl.nstat < 2){
  723. DPRINT("seek: confused\n");
  724. fl.confused = 1;
  725. return -1;
  726. }
  727. if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
  728. DPRINT("seek: failed\n");
  729. dp->confused = 1;
  730. return -1;
  731. }
  732. dp->cyl = dp->tcyl;
  733. return dp->tcyl;
  734. }
  735. /*
  736. * read or write to floppy. try up to three times.
  737. */
  738. static long
  739. floppyxfer(FDrive *dp, int cmd, void *a, long off, long n)
  740. {
  741. long offset;
  742. int tries;
  743. if(off >= dp->t->cap)
  744. return 0;
  745. if(off + n > dp->t->cap)
  746. n = dp->t->cap - off;
  747. /* retry on error (until it gets ridiculous) */
  748. tries = 0;
  749. while(waserror()){
  750. if(tries++ >= dp->maxtries)
  751. nexterror();
  752. DPRINT("floppyxfer: retrying\n");
  753. }
  754. dp->len = n;
  755. if(floppyseek(dp, off) < 0){
  756. DPRINT("xfer: seek failed\n");
  757. dp->confused = 1;
  758. error(Eio);
  759. }
  760. /*
  761. * set up the dma (dp->len may be trimmed)
  762. */
  763. if(waserror()){
  764. dmaend(DMAchan);
  765. nexterror();
  766. }
  767. dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread);
  768. if(dp->len < 0)
  769. error(Eio);
  770. /*
  771. * start operation
  772. */
  773. fl.ncmd = 0;
  774. fl.cmd[fl.ncmd++] = cmd | (dp->t->heads > 1 ? Fmulti : 0);
  775. fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
  776. fl.cmd[fl.ncmd++] = dp->tcyl;
  777. fl.cmd[fl.ncmd++] = dp->thead;
  778. fl.cmd[fl.ncmd++] = dp->tsec;
  779. fl.cmd[fl.ncmd++] = dp->t->bcode;
  780. fl.cmd[fl.ncmd++] = dp->t->sectors;
  781. fl.cmd[fl.ncmd++] = dp->t->gpl;
  782. fl.cmd[fl.ncmd++] = 0xFF;
  783. if(floppycmd() < 0)
  784. error(Eio);
  785. /* Poll ready bits and transfer data */
  786. floppyexec((char*)a, dp->len, cmd==Fread);
  787. /*
  788. * give bus to DMA, floppyintr() will read result
  789. */
  790. floppywait(0);
  791. dmaend(DMAchan);
  792. poperror();
  793. /*
  794. * check for errors
  795. */
  796. if(fl.nstat < 7){
  797. DPRINT("xfer: confused\n");
  798. fl.confused = 1;
  799. error(Eio);
  800. }
  801. if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){
  802. DPRINT("xfer: failed %ux %ux %ux\n", fl.stat[0],
  803. fl.stat[1], fl.stat[2]);
  804. DPRINT("offset %lud len %ld\n", off, dp->len);
  805. if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun){
  806. DPRINT("DMA overrun: retry\n");
  807. } else
  808. dp->confused = 1;
  809. error(Eio);
  810. }
  811. /*
  812. * check for correct cylinder
  813. */
  814. offset = fl.stat[3] * dp->t->heads + fl.stat[4];
  815. offset = offset*dp->t->sectors + fl.stat[5] - 1;
  816. offset = offset * c2b[fl.stat[6]];
  817. if(offset != off+dp->len){
  818. DPRINT("xfer: ends on wrong cyl\n");
  819. dp->confused = 1;
  820. error(Eio);
  821. }
  822. poperror();
  823. dp->lasttouched = m->ticks;
  824. return dp->len;
  825. }
  826. /*
  827. * format a track
  828. */
  829. static void
  830. floppyformat(FDrive *dp, Cmdbuf *cb)
  831. {
  832. int cyl, h, sec;
  833. ulong track;
  834. uchar *buf, *bp;
  835. FType *t;
  836. /*
  837. * set the type
  838. */
  839. if(cb->nf == 2){
  840. for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
  841. if(strcmp(cb->f[1], t->name)==0 && t->dt==dp->dt){
  842. dp->t = t;
  843. floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
  844. break;
  845. }
  846. }
  847. if(t >= &floppytype[nelem(floppytype)])
  848. error(Ebadarg);
  849. } else if(cb->nf == 1){
  850. floppysetdef(dp);
  851. t = dp->t;
  852. } else {
  853. cmderror(cb, "invalid floppy format command");
  854. SET(t);
  855. }
  856. /*
  857. * buffer for per track info
  858. */
  859. buf = smalloc(t->sectors*4);
  860. if(waserror()){
  861. free(buf);
  862. nexterror();
  863. }
  864. /* force a recalibrate to cylinder 0 */
  865. dp->confused = 1;
  866. if(!waserror()){
  867. floppyon(dp);
  868. poperror();
  869. }
  870. /*
  871. * format a track at time
  872. */
  873. for(track = 0; track < t->tracks*t->heads; track++){
  874. cyl = track/t->heads;
  875. h = track % t->heads;
  876. /*
  877. * seek to track, ignore errors
  878. */
  879. floppyseek(dp, track*t->tsize);
  880. dp->cyl = cyl;
  881. dp->confused = 0;
  882. /*
  883. * set up the dma (dp->len may be trimmed)
  884. */
  885. bp = buf;
  886. for(sec = 1; sec <= t->sectors; sec++){
  887. *bp++ = cyl;
  888. *bp++ = h;
  889. *bp++ = sec;
  890. *bp++ = t->bcode;
  891. }
  892. if(waserror()){
  893. dmaend(DMAchan);
  894. nexterror();
  895. }
  896. if(dmasetup(DMAchan, buf, bp-buf, 0) < 0)
  897. error(Eio);
  898. /*
  899. * start operation
  900. */
  901. fl.ncmd = 0;
  902. fl.cmd[fl.ncmd++] = Fformat;
  903. fl.cmd[fl.ncmd++] = (h<<2) | dp->dev;
  904. fl.cmd[fl.ncmd++] = t->bcode;
  905. fl.cmd[fl.ncmd++] = t->sectors;
  906. fl.cmd[fl.ncmd++] = t->fgpl;
  907. fl.cmd[fl.ncmd++] = 0x5a;
  908. if(floppycmd() < 0)
  909. error(Eio);
  910. /* Poll ready bits and transfer data */
  911. floppyexec((char *)buf, bp-buf, 0);
  912. /*
  913. * give bus to DMA, floppyintr() will read result
  914. */
  915. floppywait(1);
  916. dmaend(DMAchan);
  917. poperror();
  918. /*
  919. * check for errors
  920. */
  921. if(fl.nstat < 7){
  922. DPRINT("format: confused\n");
  923. fl.confused = 1;
  924. error(Eio);
  925. }
  926. if((fl.stat[0]&Codemask)!=0 || fl.stat[1]|| fl.stat[2]){
  927. DPRINT("format: failed %ux %ux %ux\n",
  928. fl.stat[0], fl.stat[1], fl.stat[2]);
  929. dp->confused = 1;
  930. error(Eio);
  931. }
  932. }
  933. free(buf);
  934. dp->confused = 1;
  935. poperror();
  936. }
  937. static void
  938. floppyintr(Ureg *)
  939. {
  940. switch(fl.cmd[0]&~Fmulti){
  941. case Fread:
  942. case Fwrite:
  943. case Fformat:
  944. case Fdumpreg:
  945. floppyresult();
  946. break;
  947. case Fseek:
  948. case Frecal:
  949. default:
  950. floppysense(); /* to clear interrupt */
  951. break;
  952. }
  953. fl.ncmd = 0;
  954. wakeup(&fl.r);
  955. }
  956. Dev floppydevtab = {
  957. 'f',
  958. "floppy",
  959. floppyreset,
  960. devinit,
  961. devshutdown,
  962. floppyattach,
  963. floppywalk,
  964. floppystat,
  965. floppyopen,
  966. devcreate,
  967. floppyclose,
  968. floppyread,
  969. devbread,
  970. floppywrite,
  971. devbwrite,
  972. devremove,
  973. devwstat,
  974. };