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