ata.c 3.3 KB

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