floppy.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. /*
  2. * Papa's got a brand new bag on the side.
  3. */
  4. #include "all.h"
  5. #include "io.h"
  6. #include "mem.h"
  7. #define DPRINT if(0)print
  8. typedef struct Floppy Floppy;
  9. typedef struct Ctlr Ctlr;
  10. typedef struct Type Type;
  11. enum
  12. {
  13. Pdor= 0x3f2, /* motor port */
  14. Fintena= 0x8, /* enable floppy interrupt */
  15. Fena= 0x4, /* 0 == reset controller */
  16. Pmsr= 0x3f4, /* controller main status port */
  17. Fready= 0x80, /* ready to be touched */
  18. Ffrom= 0x40, /* data from controller */
  19. Fbusy= 0x10, /* operation not over */
  20. Pdata= 0x3f5, /* controller data port */
  21. Frecal= 0x7, /* recalibrate cmd */
  22. Fseek= 0xf, /* seek cmd */
  23. Fsense= 0x8, /* sense cmd */
  24. Fread= 0x66, /* read cmd */
  25. Fwrite= 0x45, /* write cmd */
  26. Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */
  27. /* digital input register */
  28. Pdir= 0x3F7, /* disk changed port (read only) */
  29. Pdsr= 0x3F7, /* data rate select port (write only) */
  30. Fchange= 0x80, /* disk has changed */
  31. DMAmode0= 0xb,
  32. DMAmode1= 0xc,
  33. DMAaddr= 0x4,
  34. DMAtop= 0x81,
  35. DMAinit= 0xa,
  36. DMAcount= 0x5,
  37. Maxfloppy= 4, /* floppies/controller */
  38. /* sector size encodings */
  39. S128= 0,
  40. S256= 1,
  41. S512= 2,
  42. S1024= 3,
  43. /* status 0 byte */
  44. Floppymask= 3<<0,
  45. Seekend= 1<<5,
  46. Codemask= (3<<6)|(3<<3),
  47. Cmdexec= 1<<6,
  48. /* status 1 byte */
  49. Overrun= 0x10,
  50. };
  51. #define MOTORBIT(i) (1<<((i)+4))
  52. /*
  53. * types of drive (from PC equipment byte)
  54. */
  55. enum
  56. {
  57. T360kb= 1,
  58. T1200kb= 2,
  59. T720kb= 3,
  60. T1440kb= 4,
  61. };
  62. /*
  63. * floppy types (all MFM encoding)
  64. */
  65. struct Type
  66. {
  67. char *name;
  68. int dt; /* compatible drive type */
  69. int bytes; /* bytes/sector */
  70. int sectors; /* sectors/track */
  71. int heads; /* number of heads */
  72. int steps; /* steps per cylinder */
  73. int tracks; /* tracks/disk */
  74. int gpl; /* intersector gap length for read/write */
  75. int fgpl; /* intersector gap length for format */
  76. int rate; /* rate code */
  77. /*
  78. * these depend on previous entries and are set filled in
  79. * by floppyinit
  80. */
  81. int bcode; /* coded version of bytes for the controller */
  82. long cap; /* drive capacity in bytes */
  83. long tsize; /* track size in bytes */
  84. };
  85. Type floppytype[] =
  86. {
  87. { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
  88. { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
  89. { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
  90. { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
  91. { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, },
  92. { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
  93. };
  94. #define NTYPES (sizeof(floppytype)/sizeof(Type))
  95. /*
  96. * bytes per sector encoding for the controller.
  97. * - index for b2c is is (bytes per sector/128).
  98. * - index for c2b is code from b2c
  99. */
  100. static int b2c[] =
  101. {
  102. [1] 0,
  103. [2] 1,
  104. [4] 2,
  105. [8] 3,
  106. };
  107. static int c2b[] =
  108. {
  109. 128,
  110. 256,
  111. 512,
  112. 1024,
  113. };
  114. /*
  115. * a floppy drive
  116. */
  117. struct Floppy
  118. {
  119. Type *t;
  120. int dt;
  121. int dev;
  122. ulong lasttouched; /* time last touched */
  123. int cyl; /* current cylinder */
  124. int confused; /* needs to be recalibrated (or worse) */
  125. long offset; /* current offset */
  126. int tcyl; /* target cylinder */
  127. int thead; /* target head */
  128. int tsec; /* target sector */
  129. long len;
  130. int maxtries;
  131. };
  132. /*
  133. * NEC PD765A controller for 4 floppys
  134. */
  135. struct Ctlr
  136. {
  137. QLock;
  138. Rendez;
  139. Floppy d[Maxfloppy]; /* the floppy drives */
  140. int rw; /* true if a read or write in progress */
  141. int seek; /* one bit for each seek in progress */
  142. uchar stat[8]; /* status of an operation */
  143. int intr;
  144. int confused;
  145. int motor;
  146. Floppy *selected;
  147. int rate;
  148. int cdev;
  149. uchar *ccache; /* cyclinder cache */
  150. int ccyl;
  151. int chead;
  152. };
  153. Ctlr fl;
  154. static int floppysend(int);
  155. static int floppyrcv(void);
  156. static int floppyrdstat(int);
  157. static void floppypos(Floppy*, long);
  158. static void floppywait(char*);
  159. static int floppysense(Floppy*);
  160. static int floppyrecal(Floppy*);
  161. static void floppyon(Floppy*);
  162. static long floppyxfer(Floppy*, int, void*, long);
  163. static void floppyrevive(void);
  164. static void
  165. timedsleep(int ms)
  166. {
  167. ulong end;
  168. end = MACHP(0)->ticks + 1 + MS2TK(ms);
  169. while(MACHP(0)->ticks < end)
  170. ;
  171. }
  172. /*
  173. * set floppy drive to its default type
  174. */
  175. static void
  176. setdef(Floppy *dp)
  177. {
  178. Type *t;
  179. for(t = floppytype; t < &floppytype[NTYPES]; t++)
  180. if(dp->dt == t->dt){
  181. dp->t = t;
  182. break;
  183. }
  184. }
  185. static void
  186. floppyintr(Ureg *ur, void *arg)
  187. {
  188. USED(ur, arg);
  189. fl.intr = 1;
  190. }
  191. static void
  192. floppystop(Floppy *dp)
  193. {
  194. fl.motor &= ~MOTORBIT(dp->dev);
  195. outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
  196. }
  197. static void
  198. floppyalarm(Alarm* a, void *arg)
  199. {
  200. USED(arg);
  201. cancel(a);
  202. wakeup(&fl);
  203. }
  204. void
  205. floppyproc(void)
  206. {
  207. Floppy *dp;
  208. for(;;){
  209. for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){
  210. if((fl.motor&MOTORBIT(dp->dev))
  211. && TK2SEC(MACHP(0)->ticks - dp->lasttouched) > 5
  212. && canqlock(&fl)){
  213. if(TK2SEC(MACHP(0)->ticks - dp->lasttouched) > 5)
  214. floppystop(dp);
  215. qunlock(&fl);
  216. }
  217. }
  218. alarm(5*1000, floppyalarm, 0);
  219. sleep(&fl, no, 0);
  220. }
  221. }
  222. int
  223. floppyinit(void)
  224. {
  225. Floppy *dp;
  226. uchar equip;
  227. int nfloppy = 0;
  228. Type *t;
  229. setvec(Floppyvec, floppyintr, &fl);
  230. delay(10);
  231. outb(Pdor, 0);
  232. delay(1);
  233. outb(Pdor, Fintena | Fena);
  234. delay(10);
  235. /*
  236. * init dependent parameters
  237. */
  238. for(t = floppytype; t < &floppytype[NTYPES]; t++){
  239. t->cap = t->bytes * t->heads * t->sectors * t->tracks;
  240. t->bcode = b2c[t->bytes/128];
  241. t->tsize = t->bytes * t->sectors;
  242. }
  243. /*
  244. * init drive parameters
  245. */
  246. for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){
  247. dp->cyl = -1;
  248. dp->dev = dp - fl.d;
  249. dp->maxtries = 1;
  250. }
  251. /*
  252. * read nvram for types of floppies 0 & 1
  253. */
  254. equip = nvramread(0x10);
  255. if(Maxfloppy > 0){
  256. fl.d[0].dt = (equip >> 4) & 0xf;
  257. setdef(&fl.d[0]);
  258. nfloppy++;
  259. }
  260. if(Maxfloppy > 1){
  261. fl.d[1].dt = equip & 0xf;
  262. setdef(&fl.d[1]);
  263. nfloppy++;
  264. }
  265. fl.rate = -1;
  266. fl.motor = 0;
  267. fl.confused = 1;
  268. fl.ccyl = -1;
  269. fl.chead = -1;
  270. fl.cdev = -1;
  271. fl.ccache = (uchar*)ialloc(18*2*512, 64*1024);
  272. if(DMAOK(fl.ccache, 18*2*512) == 0)
  273. panic("floppy: no memory < 16Mb\n");
  274. return nfloppy;
  275. }
  276. static void
  277. floppyon(Floppy *dp)
  278. {
  279. int alreadyon;
  280. int tries;
  281. if(fl.confused)
  282. floppyrevive();
  283. dp->lasttouched = MACHP(0)->ticks;
  284. alreadyon = fl.motor & MOTORBIT(dp->dev);
  285. fl.motor |= MOTORBIT(dp->dev);
  286. outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
  287. /* get motor going */
  288. if(!alreadyon)
  289. timedsleep(750);
  290. /* set transfer rate */
  291. if(fl.rate != dp->t->rate){
  292. fl.rate = dp->t->rate;
  293. outb(Pdsr, fl.rate);
  294. }
  295. /* get drive to a known cylinder */
  296. if(dp->confused)
  297. for(tries = 0; tries < 4; tries++)
  298. if(floppyrecal(dp) >= 0)
  299. break;
  300. dp->lasttouched = MACHP(0)->ticks;
  301. fl.selected = dp;
  302. }
  303. static void
  304. floppyrevive(void)
  305. {
  306. Floppy *dp;
  307. /*
  308. * reset the controller if it's confused
  309. */
  310. if(fl.confused){
  311. /* reset controller and turn all motors off */
  312. fl.intr = 0;
  313. splhi();
  314. outb(Pdor, 0);
  315. delay(1);
  316. outb(Pdor, Fintena|Fena);
  317. spllo();
  318. for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++)
  319. dp->confused = 1;
  320. fl.motor = 0;
  321. floppywait("revive");
  322. fl.confused = 0;
  323. outb(Pdsr, 0);
  324. }
  325. }
  326. static int
  327. floppysend(int data)
  328. {
  329. int tries;
  330. for(tries = 0; tries < 1000; tries++){
  331. if((inb(Pmsr)&(Ffrom|Fready)) == Fready){
  332. outb(Pdata, data);
  333. return 0;
  334. }
  335. microdelay(8);
  336. }
  337. return -1;
  338. }
  339. static int
  340. floppyrcv(void)
  341. {
  342. int tries;
  343. uchar c;
  344. for(tries = 0; tries < 1000; tries++){
  345. if((inb(Pmsr)&(Ffrom|Fready)) == (Ffrom|Fready))
  346. return inb(Pdata)&0xff;
  347. microdelay(8);
  348. }
  349. DPRINT("floppyrcv returns -1 status = %ux\n", c);
  350. return -1;
  351. }
  352. static int
  353. floppyrdstat(int n)
  354. {
  355. int i;
  356. int c;
  357. for(i = 0; i < n; i++){
  358. c = floppyrcv();
  359. if(c < 0)
  360. return -1;
  361. fl.stat[i] = c;
  362. }
  363. return 0;
  364. }
  365. static void
  366. floppypos(Floppy *dp, long off)
  367. {
  368. int lsec;
  369. int cyl;
  370. lsec = off/dp->t->bytes;
  371. dp->tcyl = lsec/(dp->t->sectors*dp->t->heads);
  372. dp->tsec = (lsec % dp->t->sectors) + 1;
  373. dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
  374. /*
  375. * can't read across cylinder boundaries.
  376. * if so, decrement the bytes to be read.
  377. */
  378. lsec = (off+dp->len)/dp->t->bytes;
  379. cyl = lsec/(dp->t->sectors*dp->t->heads);
  380. if(cyl != dp->tcyl){
  381. dp->len -= (lsec % dp->t->sectors)*dp->t->bytes;
  382. dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*dp->t->bytes
  383. *dp->t->sectors;
  384. }
  385. dp->lasttouched = MACHP(0)->ticks;
  386. fl.intr = 0;
  387. }
  388. static void
  389. floppywait(char *cmd)
  390. {
  391. ulong end;
  392. end = MACHP(0)->ticks + 1 + MS2TK(750);
  393. while(MACHP(0)->ticks < end && fl.intr == 0)
  394. ;
  395. if(m->ticks > end)
  396. DPRINT("floppy timed out, cmd=%s\n", cmd);
  397. fl.intr = 0;
  398. }
  399. static int
  400. floppysense(Floppy *dp)
  401. {
  402. /*
  403. * ask for floppy status
  404. */
  405. if(floppysend(Fsense) < 0){
  406. fl.confused = 1;
  407. return -1;
  408. }
  409. if(floppyrdstat(2) < 0){
  410. fl.confused = 1;
  411. dp->confused = 1;
  412. return -1;
  413. }
  414. /*
  415. * make sure it's the right drive
  416. */
  417. if((fl.stat[0] & Floppymask) != dp->dev){
  418. DPRINT("sense failed, %ux %ux\n", fl.stat[0], fl.stat[1]);
  419. dp->confused = 1;
  420. return -1;
  421. }
  422. return 0;
  423. }
  424. static int
  425. floppyrecal(Floppy *dp)
  426. {
  427. fl.intr = 0;
  428. if(floppysend(Frecal) < 0
  429. || floppysend(dp - fl.d) < 0){
  430. DPRINT("recalibrate rejected\n");
  431. fl.confused = 0;
  432. return -1;
  433. }
  434. floppywait("recal");
  435. /*
  436. * get return values
  437. */
  438. if(floppysense(dp) < 0)
  439. return -1;
  440. /*
  441. * see what cylinder we got to
  442. */
  443. dp->tcyl = 0;
  444. dp->cyl = fl.stat[1]/dp->t->steps;
  445. if(dp->cyl != dp->tcyl){
  446. DPRINT("recalibrate went to wrong cylinder %d\n", dp->cyl);
  447. dp->confused = 1;
  448. return -1;
  449. }
  450. dp->confused = 0;
  451. return 0;
  452. }
  453. vlong
  454. floppyseek(int dev, vlong off)
  455. {
  456. Floppy *dp;
  457. dp = &fl.d[dev];
  458. floppyon(dp);
  459. floppypos(dp, off);
  460. if(dp->cyl == dp->tcyl){
  461. dp->offset = off;
  462. return off;
  463. }
  464. /*
  465. * tell floppy to seek
  466. */
  467. if(floppysend(Fseek) < 0
  468. || floppysend((dp->thead<<2) | dp->dev) < 0
  469. || floppysend(dp->tcyl * dp->t->steps) < 0){
  470. DPRINT("seek cmd failed\n");
  471. fl.confused = 1;
  472. return -1;
  473. }
  474. /*
  475. * wait for interrupt
  476. */
  477. floppywait("seek");
  478. /*
  479. * get floppy status
  480. */
  481. if(floppysense(dp) < 0)
  482. return -1;
  483. /*
  484. * see if it worked
  485. */
  486. if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
  487. DPRINT("seek failed\n");
  488. dp->confused = 1;
  489. return -1;
  490. }
  491. /*
  492. * see what cylinder we got to
  493. */
  494. dp->cyl = fl.stat[1]/dp->t->steps;
  495. if(dp->cyl != dp->tcyl){
  496. DPRINT("seek went to wrong cylinder %d instead of %d\n",
  497. dp->cyl, dp->tcyl);
  498. dp->confused = 1;
  499. return -1;
  500. }
  501. dp->offset = off;
  502. DPRINT("seek to %ld succeeded\n", dp->offset);
  503. return dp->offset;
  504. }
  505. static long
  506. floppyxfer(Floppy *dp, int cmd, void *a, long n)
  507. {
  508. ulong addr;
  509. long offset;
  510. addr = (ulong)a;
  511. /*
  512. * dma can't cross 64 k boundaries
  513. */
  514. if((addr & 0xffff0000) != ((addr+n) & 0xffff0000))
  515. n -= (addr+n)&0xffff;
  516. dp->len = n;
  517. if(floppyseek(dp->dev, dp->offset) < 0){
  518. DPRINT("xfer seek failed\n");
  519. return -1;
  520. }
  521. DPRINT("floppy %d tcyl %d, thead %d, tsec %d, addr %lux, n %ld\n",
  522. dp->dev, dp->tcyl, dp->thead, dp->tsec, addr, n);/**/
  523. /*
  524. * set up the dma
  525. */
  526. outb(DMAmode1, cmd==Fread ? 0x46 : 0x4a);
  527. outb(DMAmode0, cmd==Fread ? 0x46 : 0x4a);
  528. outb(DMAaddr, addr);
  529. outb(DMAaddr, addr>>8);
  530. outb(DMAtop, addr>>16);
  531. outb(DMAcount, n-1);
  532. outb(DMAcount, (n-1)>>8);
  533. outb(DMAinit, 2);
  534. /*
  535. * tell floppy to go
  536. */
  537. cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0);
  538. if(floppysend(cmd) < 0
  539. || floppysend((dp->thead<<2) | dp->dev) < 0
  540. || floppysend(dp->tcyl * dp->t->steps) < 0
  541. || floppysend(dp->thead) < 0
  542. || floppysend(dp->tsec) < 0
  543. || floppysend(dp->t->bcode) < 0
  544. || floppysend(dp->t->sectors) < 0
  545. || floppysend(dp->t->gpl) < 0
  546. || floppysend(0xFF) < 0){
  547. DPRINT("xfer cmd failed\n");
  548. fl.confused = 1;
  549. return -1;
  550. }
  551. floppywait("xfer");
  552. /*
  553. * get status
  554. */
  555. if(floppyrdstat(7) < 0){
  556. DPRINT("xfer status failed\n");
  557. fl.confused = 1;
  558. return -1;
  559. }
  560. if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){
  561. DPRINT("xfer failed %ux %ux %ux\n", fl.stat[0],
  562. fl.stat[1], fl.stat[2]);
  563. if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun){
  564. DPRINT("DMA overrun: retry\n");
  565. return 0;
  566. }
  567. dp->confused = 1;
  568. return -1;
  569. }
  570. offset = (fl.stat[3]/dp->t->steps) * dp->t->heads + fl.stat[4];
  571. offset = offset*dp->t->sectors + fl.stat[5] - 1;
  572. offset = offset * c2b[fl.stat[6]];
  573. if(offset != dp->offset+n){
  574. DPRINT("new offset %ld instead of %ld\n", offset, dp->offset+dp->len);
  575. dp->confused = 1;
  576. return -1;/**/
  577. }
  578. dp->offset += dp->len;
  579. return dp->len;
  580. }
  581. long
  582. floppyread(int dev, void *a, long n)
  583. {
  584. Floppy *dp;
  585. long rv, i, nn, offset, sec;
  586. uchar *aa;
  587. int tries;
  588. dp = &fl.d[dev];
  589. dp->len = n;
  590. qlock(&fl);
  591. floppypos(dp, dp->offset);
  592. offset = dp->offset;
  593. sec = dp->tsec + dp->t->sectors*dp->thead;
  594. n = dp->len;
  595. if(fl.ccyl==dp->tcyl && fl.cdev==dev)
  596. goto out;
  597. fl.ccyl = -1;
  598. fl.cdev = dev;
  599. aa = fl.ccache;
  600. nn = dp->t->bytes*dp->t->sectors*dp->t->heads;
  601. dp->offset = dp->tcyl*nn;
  602. for(rv = 0; rv < nn; rv += i){
  603. i = 0;
  604. for(tries = 0; tries < dp->maxtries; tries++){
  605. i = floppyxfer(dp, Fread, aa+rv, nn-rv);
  606. if(i > 0)
  607. break;
  608. }
  609. if(tries == dp->maxtries)
  610. break;
  611. }
  612. if(rv != nn){
  613. dp->confused = 1;
  614. return -1; // ?!!? no qunlock(&fl)? no "goto out"?
  615. }
  616. fl.ccyl = dp->tcyl;
  617. out:
  618. memmove(a, fl.ccache + dp->t->bytes*(sec-1), n);
  619. dp->offset = offset + n;
  620. dp->maxtries = 3;
  621. qunlock(&fl);
  622. return n;
  623. }
  624. long
  625. floppywrite(int dev, void *a, long n)
  626. {
  627. Floppy *dp;
  628. long rv, i, offset;
  629. uchar *aa;
  630. int tries;
  631. dp = &fl.d[dev];
  632. qlock(&fl);
  633. fl.ccyl = -1;
  634. fl.cdev = dev;
  635. dp->len = n;
  636. offset = dp->offset;
  637. aa = a;
  638. if(DMAOK(aa, n) == 0){
  639. aa = fl.ccache;
  640. memmove(aa, a, n);
  641. }
  642. for(rv = 0; rv < n; rv += i){
  643. i = 0;
  644. for(tries = 0; tries < dp->maxtries; tries++){
  645. floppypos(dp, offset+rv);
  646. i = floppyxfer(dp, Fwrite, aa+rv, n-rv);
  647. if(i > 0)
  648. break;
  649. }
  650. if(tries == dp->maxtries)
  651. break;
  652. }
  653. if(rv != n)
  654. dp->confused = 1;
  655. dp->offset = offset + rv;
  656. dp->maxtries = 20;
  657. qunlock(&fl);
  658. return rv;
  659. }