ata.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // ata.c: ATA simulator for vblade
  2. #include "config.h"
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <sys/types.h>
  6. #include "dat.h"
  7. #include "fns.h"
  8. enum {
  9. // err bits
  10. UNC = 1<<6,
  11. MC = 1<<5,
  12. IDNF = 1<<4,
  13. MCR = 1<<3,
  14. ABRT = 1<<2,
  15. NM = 1<<1,
  16. // status bits
  17. BSY = 1<<7,
  18. DRDY = 1<<6,
  19. DF = 1<<5,
  20. DRQ = 1<<3,
  21. ERR = 1<<0,
  22. };
  23. static ushort ident[256] = {
  24. [47] 0x8000,
  25. [49] 0x0200,
  26. [50] 0x4000,
  27. [83] 0x5400,
  28. [84] 0x4000,
  29. [86] 0x1400,
  30. [87] 0x4000,
  31. [93] 0x400b,
  32. };
  33. static void
  34. setfld(ushort *a, int idx, int len, char *str) // set field in ident
  35. {
  36. uchar *p;
  37. p = (uchar *)(a+idx);
  38. while (len > 0) {
  39. if (*str == 0)
  40. p[1] = ' ';
  41. else
  42. p[1] = *str++;
  43. if (*str == 0)
  44. p[0] = ' ';
  45. else
  46. p[0] = *str++;
  47. p += 2;
  48. len -= 2;
  49. }
  50. }
  51. static void
  52. setlba28(ushort *ident, vlong lba)
  53. {
  54. uchar *cp;
  55. cp = (uchar *) &ident[60];
  56. *cp++ = lba;
  57. *cp++ = lba >>= 8;
  58. *cp++ = lba >>= 8;
  59. *cp++ = (lba >>= 8) & 0xf;
  60. }
  61. static void
  62. setlba48(ushort *ident, vlong lba)
  63. {
  64. uchar *cp;
  65. cp = (uchar *) &ident[100];
  66. *cp++ = lba;
  67. *cp++ = lba >>= 8;
  68. *cp++ = lba >>= 8;
  69. *cp++ = lba >>= 8;
  70. *cp++ = lba >>= 8;
  71. *cp++ = lba >>= 8;
  72. }
  73. void
  74. atainit(void)
  75. {
  76. char buf[64];
  77. setfld(ident, 27, 40, "Coraid EtherDrive vblade");
  78. sprintf(buf, "V%d\n", VBLADE_VERSION);
  79. setfld(ident, 23, 8, buf);
  80. setfld(ident, 10, 20, "SSN HERE");
  81. }
  82. /* The ATA spec is weird in that you specify the device size as number
  83. * of sectors and then address the sectors with an offset. That means
  84. * with LBA 28 you shouldn't see an LBA of all ones. Still, we don't
  85. * check for that.
  86. */
  87. int
  88. atacmd(Ataregs *p, uchar *dp, int ndp) // do the ata cmd
  89. {
  90. vlong lba;
  91. ushort *ip;
  92. int n;
  93. enum { MAXLBA28SIZE = 0x0fffffff };
  94. extern int maxscnt;
  95. p->status = 0;
  96. switch (p->cmd) {
  97. default:
  98. p->status = DRDY | ERR;
  99. p->err = ABRT;
  100. return 0;
  101. case 0xe7: // flush cache
  102. return 0;
  103. case 0xec: // identify device
  104. if (p->sectors != 1 || ndp < 512)
  105. return -1;
  106. memmove(dp, ident, 512);
  107. ip = (ushort *)dp;
  108. if (size & ~MAXLBA28SIZE)
  109. setlba28(ip, MAXLBA28SIZE);
  110. else
  111. setlba28(ip, size);
  112. setlba48(ip, size);
  113. p->err = 0;
  114. p->status = DRDY;
  115. p->sectors = 0;
  116. return 0;
  117. case 0xe5: // check power mode
  118. p->err = 0;
  119. p->sectors = 0xff; // the device is active or idle
  120. p->status = DRDY;
  121. return 0;
  122. case 0x20: // read sectors
  123. case 0x30: // write sectors
  124. lba = p->lba & MAXLBA28SIZE;
  125. break;
  126. case 0x24: // read sectors ext
  127. case 0x34: // write sectors ext
  128. lba = p->lba & 0x0000ffffffffffffLL; // full 48
  129. break;
  130. }
  131. // we ought not be here unless we are a read/write
  132. if (p->sectors > maxscnt || p->sectors*512 > ndp)
  133. return -1;
  134. if (lba + p->sectors > size) {
  135. p->err = IDNF;
  136. p->status = DRDY | ERR;
  137. p->lba = lba;
  138. return 0;
  139. }
  140. if (p->cmd == 0x20 || p->cmd == 0x24)
  141. n = getsec(bfd, dp, lba, p->sectors);
  142. else
  143. n = putsec(bfd, dp, lba, p->sectors);
  144. n /= 512;
  145. if (n != p->sectors) {
  146. p->err = ABRT;
  147. p->status = ERR;
  148. } else
  149. p->err = 0;
  150. p->status |= DRDY;
  151. p->lba += n;
  152. p->sectors -= n;
  153. return 0;
  154. }