SayoriOS  0.3.3
atapi.c
1 
9 // Super-duper original ATAPI driver by NDRAEY (c) 2023
10 // for SayoriOS
11 
12 #include "drv/atapi.h"
13 #include "net/endianess.h"
14 #include "debug/hexview.h"
15 
16 // FIXME: Add REQUEST_SENSE command to handle errors.
17 
23 bool ata_scsi_status_wait(uint8_t bus) {
24  while (1) {
25  uint8_t status = inb(ATA_PORT(bus) + ATA_REG_COMMAND);
26 
27  if ((status & 0x01) == 1)
28  return true; // error
29 
30  if (!(status & 0x80) && (status & 0x08))
31  break;
32 
33  ide_400ns_delay(ATA_PORT(bus));
34  }
35 
36  return false;
37 }
38 
47 bool ata_scsi_send(uint16_t bus, bool slave, uint16_t lba_mid_hi, uint8_t command[12]) {
48  // qemu_log("ATAPI SCSI send [%s %s], LBA (MID AND HI): %d",
49  // PRIM_SEC(bus), MAST_SLV(slave), lba_mid_hi);
50 
51  ide_select_drive(bus, slave);
52 
53  ide_400ns_delay(ATA_PORT(bus));
54 
55  outb(ATA_PORT(bus) + ATA_REG_ERROR, 0x00);
56  outb(ATA_PORT(bus) + ATA_REG_LBA1, lba_mid_hi & 0xFF);
57  outb(ATA_PORT(bus) + ATA_REG_LBA2, (lba_mid_hi >> 8) & 0xFF);
58  outb(ATA_PORT(bus) + ATA_REG_COMMAND, ATA_CMD_PACKET);
59 
60  ide_400ns_delay(ATA_PORT(bus));
61 
62  bool error = ata_scsi_status_wait(bus);
63 
64  if(error) {
65  qemu_log("Error");
66  return error;
67  }
68 
69  outsw(ATA_PORT(bus) + ATA_REG_DATA, (uint16_t *)command, 6);
70 
71  // That's all folks!
72 
73  return false;
74 }
75 
81 size_t ata_scsi_receive_size_of_transfer(uint16_t bus) {
82  bool error = ata_scsi_status_wait(bus);
83 
84  if(error) {
85  qemu_log("ATAPI size receive error");
86  return 0;
87  }
88 
89  return (inb(ATA_PORT(bus) + ATA_REG_LBA2) << 8)
90  | inb(ATA_PORT(bus) + ATA_REG_LBA1);
91 }
92 
99 void ata_scsi_read_result(uint16_t bus, size_t size, uint16_t* buffer) {
100  insw(ATA_PORT(bus) + ATA_REG_DATA, (uint16_t*)((uint8_t *)buffer), size);
101 }
102 
109 size_t atapi_read_size(uint16_t bus, bool slave) {
110 // qemu_log("SIZE REQUEST ON (ints): %d %d", bus, slave);
111 // qemu_log("SIZE REQUEST ON: %s %s", PRIM_SEC(bus), MAST_SLV(slave));
112 
113  uint8_t command[12] = {
114  ATAPI_READ_CAPACITY,
115  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
116  };
117 
118  ata_scsi_send(bus, slave, 0x0008, command);
119 
120  size_t transf_size = ata_scsi_receive_size_of_transfer(bus);
121 
122 // qemu_log("Size of transfer is: %d", transf_size);
123 
124  if(!transf_size)
125  return 0;
126 
127  uint16_t* data = kcalloc(transf_size, 1);
128 
129  ata_scsi_read_result(bus, transf_size, data);
130 
131  uint32_t* data2 = (uint32_t*)data;
132 
133  uint32_t maxlba = data2[0];
134 // uint32_t blocksize = ntohl(data2[1]);
135 
136  maxlba = ntohl(maxlba);
137 
138 // qemu_log("Blocks: %x; Block size: %x", maxlba, blocksize);
139 
140  kfree(data);
141 
142  return maxlba;
143 }
144 
151 size_t atapi_read_block_size(uint16_t bus, bool slave) {
152  uint8_t command[12] = {
153  ATAPI_READ_CAPACITY,
154  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
155  };
156 
157  ata_scsi_send(bus, slave, 0x0008, command);
158 
159  size_t transf_size = ata_scsi_receive_size_of_transfer(bus);
160 
161  uint16_t* data = (uint16_t*)kcalloc(transf_size, 1);
162 
163  ata_scsi_read_result(bus, transf_size, data);
164 
165  uint32_t blocksize = ntohl(*((uint32_t*)(data) + 1));
166 
167  // qemu_log("Block size is: %d", blocksize);
168 
169  kfree(data);
170 
171  return blocksize;
172 }
173 
182 bool atapi_read_sectors(uint16_t drive, uint8_t *buf, uint32_t lba, size_t sector_count) {
183  uint8_t bus = (drive >> 1) & 1;
184  bool slave = (bool)((drive >> 0) & 1);
185 
186  uint8_t command[12] = {
187  ATAPI_CMD_READ, // Command
188  0, // ?
189  (lba >> 0x18) & 0xFF, // LBA
190  (lba >> 0x10) & 0xFF,
191  (lba >> 0x08) & 0xFF,
192  (lba >> 0x00) & 0xFF,
193  (sector_count >> 0x18) & 0xFF, // Sector count
194  (sector_count >> 0x10) & 0xFF,
195  (sector_count >> 0x08) & 0xFF,
196  (sector_count >> 0x00) & 0xFF,
197  0, // ?
198  0 // ?
199  };
200 
201  size_t block_size = atapi_read_block_size(bus, slave);
202  bool error = ata_scsi_send(bus, slave, block_size, command);
203 
204  if(error) {
205  qemu_log("Error");
206  return error;
207  }
208 
209  size_t transf_size = ata_scsi_receive_size_of_transfer(bus);
210 
211  if(!transf_size) {
212  qemu_log("Error: Transfer size can't be 0!");
213  return true;
214  }
215 
216  for (uint32_t i = 0; i < sector_count; i++) {
217  error = ata_scsi_status_wait(bus);
218 
219  if(error)
220  return true;
221 
222  size_t size = ata_scsi_receive_size_of_transfer(bus);
223 
224  insw(ATA_PORT(bus) + ATA_REG_DATA, (uint16_t*)((uint8_t*)buf + i * block_size), size / 2); // Read it
225  }
226 
227  return false;
228 }
229 
236 bool atapi_eject(uint8_t bus, bool slave) {
237  // Byte 4:
238  // Bit 0: Start
239  // Bit 1: LoEj
240 
241  // LoEj Start Result
242  // 0 0 Stop the Disc
243  // 0 1 Start the Disc
244  // 1 0 Eject Disc
245  // 1 1 Close the Tray (Load the Disc)
246 
247  uint8_t command[12] = {
248  ATAPI_CMD_START_STOP, // Command
249  0, 0, 0, // Reserved
250  0, // Stop disc
251  0, 0, 0, 0, 0, 0, 0 // Reserved
252  };
253 
254  bool error = ata_scsi_send(bus, slave, 0, command);
255 
256  if(error) {
257  qemu_log("Error");
258  }
259 
260  command[4] = (1 << 1); // Byte 4: LoEj: Eject disc if possible
261 
262  error = ata_scsi_send(bus, slave, 0, command);
263 
264  if(error) {
265  qemu_log("Error");
266  }
267 
268  return error;
269 }
270 
278 atapi_error_code atapi_request_sense(uint8_t bus, bool slave, uint8_t out[18]) {
279  uint8_t command[12] = {
280  ATAPI_CMD_RQ_SENSE, 0, 0, 0,
281  18, // Allocation Length: We need only 18 bytes (mininal respose length)
282  0, 0, 0, 0, 0, 0, 0
283  };
284 
285  ata_scsi_send(bus, slave, 18, command);
286 
287  ata_scsi_receive_size_of_transfer(bus);
288 
289  ata_scsi_read_result(bus, 18, (uint16_t*)out);
290 
291  // First byte should be 0xf0
292 
293  hexview_advanced(out, 18, 10, false, new_qemu_printf);
294 
295  return (atapi_error_code){(out[0] >> 7) & 1, out[2] & 0b00001111, out[12], out[13]};
296 }
297 
304 bool atapi_check_media_presence(uint8_t bus, bool slave) {
305  uint8_t command[12] = {
306  ATAPI_CMD_READY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
307  };
308 
309  bool error = ata_scsi_send(bus, slave, 0, command);
310 
311  if(error) {
312  qemu_log("Error");
313  return false;
314  }
315 
316  uint8_t errorcode[18];
317 
318  atapi_error_code error_code = atapi_request_sense(1, 0, errorcode);
319 
320  return !(error_code.valid && error_code.sense_key == 0x02 && error_code.sense_code == 0x3A);
321 }