devfloppy.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include "lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "io.h"
  15. #include "ureg.h"
  16. #include "fs.h"
  17. #include "devfloppy.h"
  18. /* Intel 82077A (8272A compatible) floppy controller */
  19. /* This module expects the following functions to be defined
  20. * elsewhere:
  21. *
  22. * inb()
  23. * outb()
  24. * floppyexec()
  25. * floppyeject()
  26. * floppysetup0()
  27. * floppysetup1()
  28. * dmainit()
  29. * dmasetup()
  30. * dmaend()
  31. *
  32. * On DMA systems, floppyexec() should be an empty function;
  33. * on non-DMA systems, dmaend() should be an empty function;
  34. * dmasetup() may enforce maximum transfer sizes.
  35. */
  36. enum {
  37. /* file types */
  38. Qdir= 0,
  39. Qdata= (1<<2),
  40. Qctl= (2<<2),
  41. Qmask= (3<<2),
  42. DMAchan= 2, /* floppy dma channel */
  43. };
  44. #define DPRINT if(0)print
  45. FType floppytype[] =
  46. {
  47. { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
  48. { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
  49. { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
  50. { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
  51. { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, },
  52. { "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, },
  53. { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
  54. };
  55. /*
  56. * bytes per sector encoding for the controller.
  57. * - index for b2c is is (bytes per sector/128).
  58. * - index for c2b is code from b2c
  59. */
  60. static int b2c[] =
  61. {
  62. [1] 0,
  63. [2] 1,
  64. [4] 2,
  65. [8] 3,
  66. };
  67. static int c2b[] =
  68. {
  69. 128,
  70. 256,
  71. 512,
  72. 1024,
  73. };
  74. FController fl;
  75. #define MOTORBIT(i) (1<<((i)+4))
  76. /*
  77. * predeclared
  78. */
  79. static int cmddone(void*);
  80. static void floppyformat(FDrive*, char*);
  81. static void floppykproc(void*);
  82. static void floppypos(FDrive*,int32_t);
  83. static int floppyrecal(FDrive*);
  84. static int floppyresult(void);
  85. static void floppyrevive(void);
  86. static int64_t pcfloppyseek(FDrive*, int64_t);
  87. static int floppysense(void);
  88. static void floppywait(int);
  89. static int32_t floppyxfer(FDrive*, int, void*, int32_t, int32_t);
  90. static void
  91. fldump(void)
  92. {
  93. DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb),
  94. inb(Pdor), inb(Pmsr), inb(Pdir));
  95. }
  96. static void
  97. floppyalarm(Alarm* a)
  98. {
  99. FDrive *dp;
  100. for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
  101. if((fl.motor&MOTORBIT(dp->dev)) && TK2SEC(machp()->ticks - dp->lasttouched) > 5)
  102. floppyoff(dp);
  103. }
  104. alarm(5*1000, floppyalarm, 0);
  105. cancel(a);
  106. }
  107. /*
  108. * set floppy drive to its default type
  109. */
  110. static void
  111. floppysetdef(FDrive *dp)
  112. {
  113. FType *t;
  114. for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++)
  115. if(dp->dt == t->dt){
  116. dp->t = t;
  117. break;
  118. }
  119. }
  120. static void
  121. _floppydetach(void)
  122. {
  123. /*
  124. * stop the motors
  125. */
  126. fl.motor = 0;
  127. delay(10);
  128. outb(Pdor, fl.motor | Fintena | Fena);
  129. delay(10);
  130. }
  131. int
  132. floppyinit(void)
  133. {
  134. FDrive *dp;
  135. FType *t;
  136. uint32_t maxtsize;
  137. int mask;
  138. dmainit(DMAchan);
  139. floppysetup0(&fl);
  140. /*
  141. * init dependent parameters
  142. */
  143. maxtsize = 0;
  144. for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
  145. t->cap = t->bytes * t->heads * t->sectors * t->tracks;
  146. t->bcode = b2c[t->bytes/128];
  147. t->tsize = t->bytes * t->sectors;
  148. if(maxtsize < t->tsize)
  149. maxtsize = t->tsize;
  150. }
  151. fl.selected = fl.d;
  152. floppydetach = _floppydetach;
  153. floppydetach();
  154. /*
  155. * init drives
  156. */
  157. mask = 0;
  158. for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
  159. dp->dev = dp - fl.d;
  160. if(dp->dt == Tnone)
  161. continue;
  162. mask |= 1<<dp->dev;
  163. floppysetdef(dp);
  164. dp->cyl = -1; /* because we don't know */
  165. dp->cache = (uint8_t*)xspanalloc(maxtsize, BY2PG, 64*1024);
  166. dp->ccyl = -1;
  167. dp->vers = 0;
  168. dp->maxtries = 5;
  169. }
  170. /*
  171. * first operation will recalibrate
  172. */
  173. fl.confused = 1;
  174. floppysetup1(&fl);
  175. /* to turn the motor off when inactive */
  176. alarm(5*1000, floppyalarm, 0);
  177. return mask;
  178. }
  179. void
  180. floppyinitdev(int i, char *name)
  181. {
  182. if(i >= fl.ndrive)
  183. panic("floppyinitdev");
  184. sprint(name, "fd%d", i);
  185. }
  186. void
  187. floppyprintdevs(int i)
  188. {
  189. if(i >= fl.ndrive)
  190. panic("floppyprintdevs");
  191. print(" fd%d", i);
  192. }
  193. int
  194. floppyboot(int dev, char *file, Boot *b)
  195. {
  196. Fs *fs;
  197. if(strncmp(file, "dos!", 4) == 0)
  198. file += 4;
  199. else if(strchr(file, '!') || strcmp(file, "")==0) {
  200. print("syntax is fd0!file\n");
  201. return -1;
  202. }
  203. fs = floppygetfspart(dev, "dos", 1);
  204. if(fs == nil)
  205. return -1;
  206. return fsboot(fs, file, b);
  207. }
  208. void
  209. floppyprintbootdevs(int dev)
  210. {
  211. print(" fd%d", dev);
  212. }
  213. /*
  214. * check if the floppy has been replaced under foot. cause
  215. * an error if it has.
  216. *
  217. * a seek and a read clears the condition. this was determined
  218. * experimentally, there has to be a better way.
  219. *
  220. * if the read fails, cycle through the possible floppy
  221. * density till one works or we've cycled through all
  222. * possibilities for this drive.
  223. */
  224. static int
  225. changed(FDrive *dp)
  226. {
  227. FType *start;
  228. /*
  229. * if floppy has changed or first time through
  230. */
  231. if((inb(Pdir)&Fchange) || dp->vers == 0){
  232. DPRINT("changed\n");
  233. fldump();
  234. dp->vers++;
  235. floppysetdef(dp);
  236. dp->maxtries = 3;
  237. start = dp->t;
  238. /* flopppyon fails if there's no drive */
  239. dp->confused = 1; /* make floppyon recal */
  240. if(floppyon(dp) < 0)
  241. return -1;
  242. pcfloppyseek(dp, dp->t->heads*dp->t->tsize);
  243. while(floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize) <= 0){
  244. /*
  245. * if the xfer attempt doesn't clear the changed bit,
  246. * there's no floppy in the drive
  247. */
  248. if(inb(Pdir)&Fchange)
  249. return -1;
  250. while(++dp->t){
  251. if(dp->t == &floppytype[nelem(floppytype)])
  252. dp->t = floppytype;
  253. if(dp->dt == dp->t->dt)
  254. break;
  255. }
  256. /* flopppyon fails if there's no drive */
  257. if(floppyon(dp) < 0)
  258. return -1;
  259. DPRINT("changed: trying %s\n", dp->t->name);
  260. fldump();
  261. if(dp->t == start)
  262. return -1;
  263. }
  264. }
  265. return 0;
  266. }
  267. static int
  268. readtrack(FDrive *dp, int cyl, int head)
  269. {
  270. int i, nn, sofar;
  271. uint32_t pos;
  272. nn = dp->t->tsize;
  273. if(dp->ccyl==cyl && dp->chead==head)
  274. return nn;
  275. pos = (cyl*dp->t->heads+head) * nn;
  276. for(sofar = 0; sofar < nn; sofar += i){
  277. dp->ccyl = -1;
  278. i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar);
  279. if(i <= 0)
  280. return -1;
  281. }
  282. dp->ccyl = cyl;
  283. dp->chead = head;
  284. return nn;
  285. }
  286. int32_t
  287. floppyread(Fs *fs, void *a, int32_t n)
  288. {
  289. FDrive *dp;
  290. int32_t rv, offset;
  291. int sec, head, cyl;
  292. int32_t len;
  293. uint8_t *aa;
  294. aa = a;
  295. dp = &fl.d[fs->dev];
  296. offset = dp->offset;
  297. floppyon(dp);
  298. if(changed(dp))
  299. return -1;
  300. for(rv = 0; rv < n; rv += len){
  301. /*
  302. * all xfers come out of the track cache
  303. */
  304. dp->len = n - rv;
  305. floppypos(dp, offset+rv);
  306. cyl = dp->tcyl;
  307. head = dp->thead;
  308. len = dp->len;
  309. sec = dp->tsec;
  310. if(readtrack(dp, cyl, head) < 0)
  311. break;
  312. memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len);
  313. }
  314. dp->offset = offset+rv;
  315. return rv;
  316. }
  317. void*
  318. floppygetfspart(int i, char *name, int chatty)
  319. {
  320. static Fs fs;
  321. if(strcmp(name, "dos") != 0){
  322. if(chatty)
  323. print("unknown partition fd%d!%s (use fd%d!dos)\n", i, name, i);
  324. return nil;
  325. }
  326. fs.dev = i;
  327. fs.diskread = floppyread;
  328. fs.diskseek = floppyseek;
  329. /* sometimes we get spurious errors and doing it again works */
  330. if(dosinit(&fs) < 0 && dosinit(&fs) < 0){
  331. if(chatty)
  332. print("fd%d!%s does not contain a FAT file system\n", i, name);
  333. return nil;
  334. }
  335. return &fs;
  336. }
  337. static int
  338. return0(void*)
  339. {
  340. return 0;
  341. }
  342. static void
  343. timedsleep(int (*f)(void*), void* arg, int ms)
  344. {
  345. int s;
  346. uint32_t end;
  347. end = machp()->ticks + 1 + MS2TK(ms);
  348. while(machp()->ticks < end && !(*f)(arg)){
  349. s = spllo();
  350. delay(10);
  351. splx(s);
  352. }
  353. }
  354. /*
  355. * start a floppy drive's motor.
  356. */
  357. static int
  358. floppyon(FDrive *dp)
  359. {
  360. int alreadyon;
  361. int tries;
  362. if(fl.confused)
  363. floppyrevive();
  364. /* start motor and select drive */
  365. dp->lasttouched = machp()->ticks;
  366. alreadyon = fl.motor & MOTORBIT(dp->dev);
  367. if(!alreadyon){
  368. fl.motor |= MOTORBIT(dp->dev);
  369. outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
  370. /* wait for drive to spin up */
  371. timedsleep(return0, 0, 750);
  372. /* clear any pending interrupts */
  373. floppysense();
  374. }
  375. /* set transfer rate */
  376. if(fl.rate != dp->t->rate){
  377. fl.rate = dp->t->rate;
  378. outb(Pdsr, fl.rate);
  379. }
  380. /* get drive to a known cylinder */
  381. if(dp->confused)
  382. for(tries = 0; tries < 4; tries++)
  383. if(floppyrecal(dp) >= 0)
  384. break;
  385. dp->lasttouched = machp()->ticks;
  386. fl.selected = dp;
  387. if(dp->confused)
  388. return -1;
  389. return 0;
  390. }
  391. /*
  392. * stop the floppy if it hasn't been used in 5 seconds
  393. */
  394. static void
  395. floppyoff(FDrive *dp)
  396. {
  397. fl.motor &= ~MOTORBIT(dp->dev);
  398. outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
  399. }
  400. /*
  401. * send a command to the floppy
  402. */
  403. static int
  404. floppycmd(void)
  405. {
  406. int i;
  407. int tries;
  408. fl.nstat = 0;
  409. for(i = 0; i < fl.ncmd; i++){
  410. for(tries = 0; ; tries++){
  411. if((inb(Pmsr)&(Ffrom|Fready)) == Fready)
  412. break;
  413. if(tries > 1000){
  414. DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i);
  415. fldump();
  416. /* empty fifo, might have been a bad command */
  417. floppyresult();
  418. return -1;
  419. }
  420. microdelay(1);
  421. }
  422. outb(Pfdata, fl.cmd[i]);
  423. }
  424. return 0;
  425. }
  426. /*
  427. * get a command result from the floppy
  428. *
  429. * when the controller goes ready waiting for a command
  430. * (instead of sending results), we're done
  431. *
  432. */
  433. static int
  434. floppyresult(void)
  435. {
  436. int i, s;
  437. int tries;
  438. /* get the result of the operation */
  439. for(i = 0; i < sizeof(fl.stat); i++){
  440. /* wait for status byte */
  441. for(tries = 0; ; tries++){
  442. s = inb(Pmsr)&(Ffrom|Fready);
  443. if(s == Fready){
  444. fl.nstat = i;
  445. return fl.nstat;
  446. }
  447. if(s == (Ffrom|Fready))
  448. break;
  449. if(tries > 1000){
  450. DPRINT("floppyresult: %d stats\n", i);
  451. fldump();
  452. fl.confused = 1;
  453. return -1;
  454. }
  455. microdelay(1);
  456. }
  457. fl.stat[i] = inb(Pfdata);
  458. }
  459. fl.nstat = sizeof(fl.stat);
  460. return fl.nstat;
  461. }
  462. /*
  463. * calculate physical address of a logical byte offset into the disk
  464. *
  465. * truncate dp->length if it crosses a track boundary
  466. */
  467. static void
  468. floppypos(FDrive *dp, int32_t off)
  469. {
  470. int lsec;
  471. int ltrack;
  472. int end;
  473. lsec = off/dp->t->bytes;
  474. ltrack = lsec/dp->t->sectors;
  475. dp->tcyl = ltrack/dp->t->heads;
  476. dp->tsec = (lsec % dp->t->sectors) + 1;
  477. dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
  478. /*
  479. * can't read across track boundaries.
  480. * if so, decrement the bytes to be read.
  481. */
  482. end = (ltrack+1)*dp->t->sectors*dp->t->bytes;
  483. if(off+dp->len > end)
  484. dp->len = end - off;
  485. }
  486. /*
  487. * get the interrupt cause from the floppy.
  488. */
  489. static int
  490. floppysense(void)
  491. {
  492. fl.ncmd = 0;
  493. fl.cmd[fl.ncmd++] = Fsense;
  494. if(floppycmd() < 0)
  495. return -1;
  496. if(floppyresult() < 2){
  497. DPRINT("can't read sense response\n");
  498. fldump();
  499. fl.confused = 1;
  500. return -1;
  501. }
  502. return 0;
  503. }
  504. static int
  505. cmddone(void *a)
  506. {
  507. USED(a);
  508. return fl.ncmd == 0;
  509. }
  510. /*
  511. * Wait for a floppy interrupt. If none occurs in 5 seconds, we
  512. * may have missed one. This only happens on some portables which
  513. * do power management behind our backs. Call the interrupt
  514. * routine to try to clear any conditions.
  515. */
  516. static void
  517. floppywait(int slow)
  518. {
  519. timedsleep(cmddone, 0, slow ? 5000 : 1000);
  520. if(!cmddone(0)){
  521. floppyintr(0);
  522. fl.confused = 1;
  523. }
  524. }
  525. /*
  526. * we've lost the floppy position, go to cylinder 0.
  527. */
  528. static int
  529. floppyrecal(FDrive *dp)
  530. {
  531. dp->ccyl = -1;
  532. dp->cyl = -1;
  533. fl.ncmd = 0;
  534. fl.cmd[fl.ncmd++] = Frecal;
  535. fl.cmd[fl.ncmd++] = dp->dev;
  536. if(floppycmd() < 0)
  537. return -1;
  538. floppywait(1);
  539. if(fl.nstat < 2){
  540. DPRINT("recalibrate: confused %ux\n", inb(Pmsr));
  541. fl.confused = 1;
  542. return -1;
  543. }
  544. if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
  545. DPRINT("recalibrate: failed\n");
  546. dp->confused = 1;
  547. return -1;
  548. }
  549. dp->cyl = fl.stat[1];
  550. if(dp->cyl != 0){
  551. DPRINT("recalibrate: wrong cylinder %d\n", dp->cyl);
  552. dp->cyl = -1;
  553. dp->confused = 1;
  554. return -1;
  555. }
  556. dp->confused = 0;
  557. return 0;
  558. }
  559. /*
  560. * if the controller or a specific drive is in a confused state,
  561. * reset it and get back to a kown state
  562. */
  563. static void
  564. floppyrevive(void)
  565. {
  566. FDrive *dp;
  567. /*
  568. * reset the controller if it's confused
  569. */
  570. if(fl.confused){
  571. DPRINT("floppyrevive in\n");
  572. fldump();
  573. /* reset controller and turn all motors off */
  574. splhi();
  575. fl.ncmd = 1;
  576. fl.cmd[0] = 0;
  577. outb(Pdor, 0);
  578. delay(10);
  579. outb(Pdor, Fintena|Fena);
  580. delay(10);
  581. spllo();
  582. fl.motor = 0;
  583. fl.confused = 0;
  584. floppywait(0);
  585. /* mark all drives in an unknown state */
  586. for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++)
  587. dp->confused = 1;
  588. /* set rate to a known value */
  589. outb(Pdsr, 0);
  590. fl.rate = 0;
  591. DPRINT("floppyrevive out\n");
  592. fldump();
  593. }
  594. }
  595. /*
  596. * seek to the target cylinder
  597. *
  598. * interrupt, no results
  599. */
  600. static int64_t
  601. pcfloppyseek(FDrive *dp, int64_t off)
  602. {
  603. floppypos(dp, off);
  604. if(dp->cyl == dp->tcyl){
  605. dp->offset = off;
  606. return off;
  607. }
  608. dp->cyl = -1;
  609. fl.ncmd = 0;
  610. fl.cmd[fl.ncmd++] = Fseek;
  611. fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
  612. fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps;
  613. if(floppycmd() < 0)
  614. return -1;
  615. floppywait(1);
  616. if(fl.nstat < 2){
  617. DPRINT("seek: confused\n");
  618. fl.confused = 1;
  619. return -1;
  620. }
  621. if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
  622. DPRINT("seek: failed\n");
  623. dp->confused = 1;
  624. return -1;
  625. }
  626. dp->cyl = dp->tcyl;
  627. dp->offset = off;
  628. DPRINT("seek to %d succeeded\n", dp->offset);
  629. return dp->offset;
  630. }
  631. /*
  632. * read or write to floppy. try up to three times.
  633. */
  634. static int32_t
  635. floppyxfer(FDrive *dp, int cmd, void *a, int32_t off, int32_t n)
  636. {
  637. int32_t offset;
  638. int tries;
  639. if(off >= dp->t->cap)
  640. return 0;
  641. if(off + n > dp->t->cap)
  642. n = dp->t->cap - off;
  643. /* retry on error (until it gets ridiculous) */
  644. for(tries = 0; tries < dp->maxtries; tries++){
  645. dp->len = n;
  646. if(pcfloppyseek(dp, off) < 0){
  647. DPRINT("xfer: seek failed\n");
  648. dp->confused = 1;
  649. continue;
  650. }
  651. /*
  652. * set up the dma (dp->len may be trimmed)
  653. */
  654. dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread);
  655. if(dp->len < 0){
  656. buggery:
  657. dmaend(DMAchan);
  658. continue;
  659. }
  660. /*
  661. * start operation
  662. */
  663. fl.ncmd = 0;
  664. fl.cmd[fl.ncmd++] = cmd | (dp->t->heads > 1 ? Fmulti : 0);
  665. fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
  666. fl.cmd[fl.ncmd++] = dp->tcyl;
  667. fl.cmd[fl.ncmd++] = dp->thead;
  668. fl.cmd[fl.ncmd++] = dp->tsec;
  669. fl.cmd[fl.ncmd++] = dp->t->bcode;
  670. fl.cmd[fl.ncmd++] = dp->t->sectors;
  671. fl.cmd[fl.ncmd++] = dp->t->gpl;
  672. fl.cmd[fl.ncmd++] = 0xFF;
  673. if(floppycmd() < 0)
  674. goto buggery;
  675. /*
  676. * give bus to DMA, floppyintr() will read result
  677. */
  678. floppywait(0);
  679. dmaend(DMAchan);
  680. /*
  681. * check for errors
  682. */
  683. if(fl.nstat < 7){
  684. DPRINT("xfer: confused\n");
  685. fl.confused = 1;
  686. continue;
  687. }
  688. if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){
  689. DPRINT("xfer: failed %ux %ux %ux\n", fl.stat[0],
  690. fl.stat[1], fl.stat[2]);
  691. DPRINT("offset %lud len %ld\n", off, dp->len);
  692. if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun){
  693. DPRINT("DMA overrun: retry\n");
  694. } else
  695. dp->confused = 1;
  696. continue;
  697. }
  698. /*
  699. * check for correct cylinder
  700. */
  701. offset = fl.stat[3] * dp->t->heads + fl.stat[4];
  702. offset = offset*dp->t->sectors + fl.stat[5] - 1;
  703. offset = offset * c2b[fl.stat[6]];
  704. if(offset != off+dp->len){
  705. DPRINT("xfer: ends on wrong cyl\n");
  706. dp->confused = 1;
  707. continue;
  708. }
  709. dp->lasttouched = machp()->ticks;
  710. dp->maxtries = 20;
  711. return dp->len;
  712. }
  713. return -1;
  714. }
  715. /*
  716. void
  717. floppymemwrite(void)
  718. {
  719. int i;
  720. int n;
  721. uchar *a;
  722. FDrive *dp;
  723. dp = &fl.d[0];
  724. a = (uchar*)0x80000000;
  725. n = 0;
  726. while(n < 1440*1024){
  727. i = floppyxfer(dp, Fwrite, a+n, n, 1440*1024-n);
  728. if(i <= 0)
  729. break;
  730. n += i;
  731. }
  732. print("floppymemwrite wrote %d bytes\n", n);
  733. splhi(); for(;;);
  734. }
  735. */
  736. static void
  737. floppyintr(Ureg *ur)
  738. {
  739. USED(ur);
  740. switch(fl.cmd[0]&~Fmulti){
  741. case Fread:
  742. case Fwrite:
  743. case Fformat:
  744. case Fdumpreg:
  745. floppyresult();
  746. break;
  747. case Fseek:
  748. case Frecal:
  749. default:
  750. floppysense(); /* to clear interrupt */
  751. break;
  752. }
  753. fl.ncmd = 0;
  754. }