devfloppy.c 20 KB

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