Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


7667e97aa8960e85eb24c9d4105e8372c5baaf0f
[palacios.git] / palacios / src / devices / atapi.h
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #ifndef __DEVICES_ATAPI_H__
21 #define __DEVICES_ATAPI_H__
22
23 #define ATAPI_PACKET_SIZE 12
24
25 #include "atapi-types.h"
26
27
28 /* ACS-2 T13/2015-D Table B.2 Command codes */
29 #define ATAPI_NOP                               0x00
30 #define CFA_REQ_EXT_ERROR_CODE          0x03 
31 #define ATAPI_DSM                         0x06
32 #define ATAPI_DEVICE_RESET              0x08
33 #define ATAPI_RECAL                       0x10 
34 #define ATAPI_READ                      0x20 
35 #define ATAPI_READ_ONCE                   0x21 
36 #define ATAPI_READ_EXT                  0x24 
37 #define ATAPI_READDMA_EXT                       0x25 
38 #define ATAPI_READDMA_QUEUED_EXT          0x26 
39 #define ATAPI_READ_NATIVE_MAX_EXT               0x27 
40 #define ATAPI_MULTREAD_EXT              0x29 
41 #define ATAPI_WRITE                     0x30 
42 #define ATAPI_WRITE_ONCE                  0x31 
43 #define ATAPI_WRITE_EXT                 0x34 
44 #define ATAPI_WRITEDMA_EXT              0x35 
45 #define ATAPI_WRITEDMA_QUEUED_EXT               0x36 
46 #define ATAPI_SET_MAX_EXT                 0x37 
47 #define ATAPI_SET_MAX_EXT                       0x37 
48 #define CFA_WRITE_SECT_WO_ERASE         0x38 
49 #define ATAPI_MULTWRITE_EXT             0x39 
50 #define ATAPI_WRITE_VERIFY                0x3C 
51 #define ATAPI_VERIFY                    0x40 
52 #define ATAPI_VERIFY_ONCE                 0x41 
53 #define ATAPI_VERIFY_EXT                        0x42 
54 #define ATAPI_SEEK                        0x70 
55 #define CFA_TRANSLATE_SECTOR            0x87 
56 #define ATAPI_DIAGNOSE                  0x90
57 #define ATAPI_SPECIFY                     0x91 
58 #define ATAPI_DOWNLOAD_MICROCODE                0x92
59 #define ATAPI_STANDBYNOW2                 0x94 
60 #define ATAPI_IDLEIMMEDIATE2              0x95 
61 #define ATAPI_STANDBY2                    0x96 
62 #define ATAPI_SETIDLE2                    0x97 
63 #define ATAPI_CHECKPOWERMODE2             0x98 
64 #define ATAPI_SLEEPNOW2                   0x99 
65 #define ATAPI_PACKETCMD                 0xA0 
66 #define ATAPI_PIDENTIFY                 0xA1 
67 #define ATAPI_QUEUED_SERVICE              0xA2 
68 #define ATAPI_SMART                     0xB0 
69 #define CFA_ACCESS_METADATA_STORAGE     0xB8
70 #define CFA_ERASE_SECTORS               0xC0 
71 #define ATAPI_MULTREAD                  0xC4 
72 #define ATAPI_MULTWRITE                 0xC5 
73 #define ATAPI_SETMULT                   0xC6 
74 #define ATAPI_READDMA                   0xC8 
75 #define ATAPI_READDMA_ONCE                0xC9 
76 #define ATAPI_WRITEDMA                  0xCA 
77 #define ATAPI_WRITEDMA_ONCE               0xCB 
78 #define ATAPI_WRITEDMA_QUEUED           0xCC 
79 #define CFA_WRITE_MULTI_WO_ERASE        0xCD 
80 #define ATAPI_GETMEDIASTATUS              0xDA 
81 #define ATAPI_DOORLOCK                    0xDE 
82 #define ATAPI_DOORUNLOCK                  0xDF 
83 #define ATAPI_STANDBYNOW1                       0xE0
84 #define ATAPI_IDLEIMMEDIATE             0xE1 
85 #define ATAPI_STANDBY                   0xE2 
86 #define ATAPI_SETIDLE1                  0xE3
87 #define ATAPI_READ_BUFFER                       0xE4 
88 #define ATAPI_CHECKPOWERMODE1           0xE5
89 #define ATAPI_SLEEPNOW1                 0xE6
90 #define ATAPI_FLUSH_CACHE                       0xE7
91 #define ATAPI_WRITE_BUFFER              0xE8 
92 #define ATAPI_FLUSH_CACHE_EXT           0xEA 
93 #define ATAPI_IDENTIFY                  0xEC 
94 #define ATAPI_MEDIAEJECT                  0xED 
95 #define ATAPI_SETFEATURES                       0xEF 
96 #define IBM_SENSE_CONDITION             0xF0 
97 #define ATAPI_SECURITY_SET_PASS         0xF1
98 #define ATAPI_SECURITY_UNLOCK           0xF2
99 #define ATAPI_SECURITY_ERASE_PREPARE    0xF3
100 #define ATAPI_SECURITY_ERASE_UNIT               0xF4
101 #define ATAPI_SECURITY_FREEZE_LOCK      0xF5
102 #define CFA_WEAR_LEVEL                  0xF5 
103 #define ATAPI_SECURITY_DISABLE          0xF6
104
105 /* ATAPI sucks...
106  * The OS will write to the cylinder register the number of bytes it wants to read 
107  * however the device can change that value 
108  * 
109  */
110 static int atapi_update_req_len(struct ide_internal * ide, struct ide_channel * channel, uint_t xfer_len) {
111     struct ide_drive * drive = get_selected_drive(channel);
112
113     //PrintDebug("\tUpdating request length (pre=%d)\n", drive->req_len);
114
115     if (drive->req_len == 0) {
116         PrintError(VM_NONE,VCORE_NONE, "ATAPI Error: request of length 0\n");
117         return -1;
118     }
119
120
121     channel->status.busy = 0;
122     channel->status.data_req = 1;
123     channel->status.error = 0;
124
125     drive->irq_flags.io_dir = 1;
126     drive->irq_flags.c_d = 0;
127
128     // make count even
129     if (drive->req_len % 2) {
130         drive->req_len -= 1;
131     }
132
133     // if the device can't return as much as the OS requested
134     // this is actually a decrement of the req_len by the amount requested by the OS
135     if (drive->req_len > xfer_len) {
136         drive->req_len = xfer_len;
137     }
138
139     //    PrintDebug("\tUpdating request length (post=%d)\n", drive->req_len);
140
141     return 0;
142 }
143
144
145
146 // This is for simple commands that don't need to sanity check the req_len
147 static void atapi_setup_cmd_resp(struct ide_internal * ide, struct ide_channel * channel, uint_t xfer_len) {
148     struct ide_drive * drive = get_selected_drive(channel);
149
150     drive->transfer_length = xfer_len;
151     drive->transfer_index = 0;
152     drive->req_len = drive->transfer_length;
153
154     drive->irq_flags.io_dir = 1;
155     drive->irq_flags.c_d = 0;
156
157     channel->status.busy = 0;
158     channel->status.error = 0;
159
160     if (drive->transfer_length > 0) {
161         channel->status.data_req = 1;
162     }
163
164     ide_raise_irq(ide, channel);
165 }
166
167 static void atapi_cmd_error(struct ide_internal * ide, struct ide_channel * channel, 
168                      atapi_sense_key_t  sense_key, atapi_add_sense_code_t asc) {
169     struct ide_drive * drive = get_selected_drive(channel);
170
171     // overload error register with ATAPI value
172     channel->error_reg.val = sense_key << 4;
173     
174     channel->status.busy = 0;
175     channel->status.ready = 1;
176     channel->status.write_fault = 0;
177     channel->status.data_req = 0;
178     channel->status.error = 1;
179   
180     drive->cd_state.sense.header = 0xf0;
181     drive->cd_state.sense.rsvd1 = 0x00;
182     drive->cd_state.sense.read_len = 0x0a;
183     drive->cd_state.sense.sense_key = sense_key;
184     drive->cd_state.sense.asc = asc;
185
186
187     drive->irq_flags.io_dir = 1;
188     drive->irq_flags.c_d = 1;
189     drive->irq_flags.rel = 0;
190
191     ide_raise_irq(ide, channel);
192 }
193
194
195 static void atapi_cmd_nop(struct ide_internal * ide, struct ide_channel * channel) {
196     struct ide_drive * drive = get_selected_drive(channel);
197
198     channel->status.busy = 0;
199     channel->status.ready = 1;
200     channel->status.data_req = 0;
201     channel->status.error = 0;
202
203     drive->irq_flags.io_dir = 1;
204     drive->irq_flags.c_d = 1;
205     drive->irq_flags.rel = 0;
206
207     ide_raise_irq(ide, channel);
208 }
209
210
211
212 static int atapi_read_chunk(struct ide_internal * ide, struct ide_channel * channel) {
213     struct ide_drive * drive = get_selected_drive(channel);
214
215     int ret = drive->ops->read(drive->data_buf, 
216                                drive->current_lba * ATAPI_BLOCK_SIZE, 
217                                ATAPI_BLOCK_SIZE, drive->private_data);
218     
219     if (ret == -1) {
220         PrintError(VM_NONE,VCORE_NONE, "IDE: Error reading CD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba));
221         return -1;
222     }
223
224     return 0;
225 }
226
227
228 static int atapi_update_data_buf(struct ide_internal * ide, struct ide_channel * channel) {
229     struct ide_drive * drive = get_selected_drive(channel);    
230     
231     switch (drive->cd_state.atapi_cmd) {
232         case 0x28: // read(10)
233         case 0xa8: // read(12)
234
235             // Update lba address to point to next block  
236             drive->current_lba++;
237
238             // read the next block
239             return atapi_read_chunk(ide, channel);
240
241         default:
242             PrintError(VM_NONE,VCORE_NONE, "Unhandled ATAPI command in update buffer %x\n", drive->cd_state.atapi_cmd);
243             return -1;
244     }
245
246     return 0;
247 }
248
249 static int atapi_read10(struct guest_info * core, 
250                         struct ide_internal * ide,
251                         struct ide_channel * channel) {
252     struct ide_drive * drive = get_selected_drive(channel);
253     struct atapi_read10_cmd * cmd = (struct atapi_read10_cmd *)(drive->data_buf);
254     uint32_t lba =  be_to_le_32(cmd->lba);
255     uint16_t xfer_len = be_to_le_16(cmd->xfer_len);
256
257     PrintDebug(core->vm_info, core, "READ10: XferLen=%d ; LBA=%x \n", xfer_len, lba );
258
259     /* Check if cd is ready
260      * if not: atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
261      */
262     
263     if (xfer_len == 0) {
264         atapi_cmd_nop(ide, channel);
265         return 0;
266     }
267     
268     if ((lba + xfer_len) > (drive->ops->get_capacity(drive->private_data) / ATAPI_BLOCK_SIZE)) {
269         PrintError(core->vm_info, core, "IDE: xfer len exceeded capacity (lba=%d) (xfer_len=%d) (ReadEnd=%d) (capacity=%d)\n", 
270                    lba, xfer_len, lba + xfer_len, 
271                    (uint32_t)drive->ops->get_capacity(drive->private_data));
272         atapi_cmd_error(ide, channel, ATAPI_SEN_ILL_REQ, ASC_LOG_BLK_OOR);
273         ide_raise_irq(ide, channel);
274         return 0;
275     }
276         
277     // PrintDebug(core->vm_info, core, "Reading %d blocks from LBA 0x%x\n", xfer_len, lba);
278     drive->current_lba = lba;
279         
280     // Update the request length value in the cylinder registers
281     drive->transfer_length = xfer_len * ATAPI_BLOCK_SIZE;
282     drive->transfer_index = 0;  
283
284     if (channel->features.dma) {
285
286         if (channel->dma_status.active == 1) {
287             if (dma_read(core, ide, channel) == -1) {
288                 PrintError(core->vm_info, core, "Error in DMA read for CD Read10 command\n");
289                 return -1;
290             }
291         }
292         return 0;
293     }
294
295     if (atapi_read_chunk(ide, channel) == -1) {
296         PrintError(core->vm_info, core, "IDE: Could not read initial chunk from CD\n");
297         return -1;
298     }
299         
300     // Length of ATAPI buffer sits in cylinder registers
301     // This is weird... The host sets this value to say what it would like to transfer, 
302     // if it is larger than the correct size, the device shrinks it to the correct size
303     if (atapi_update_req_len(ide, channel, ATAPI_BLOCK_SIZE) == -1) {
304         PrintError(core->vm_info, core, "Could not update initial request length\n");
305         return -1;
306     }
307     
308     ide_raise_irq(ide, channel);
309
310     return 0;
311 }
312
313
314
315 static void atapi_req_sense(struct ide_internal * ide, struct ide_channel * channel) {
316     struct ide_drive * drive = get_selected_drive(channel);
317
318     memcpy(drive->data_buf, drive->cd_state.sense.buf, sizeof(drive->cd_state.sense.buf));
319    
320     atapi_setup_cmd_resp(ide, channel, 18);
321 }
322
323
324
325 static int atapi_get_capacity(struct ide_internal * ide, struct ide_channel * channel) {
326     struct ide_drive * drive = get_selected_drive(channel);
327     struct atapi_rd_capacity_resp * resp = (struct atapi_rd_capacity_resp *)(drive->data_buf);
328     uint32_t capacity = drive->ops->get_capacity(drive->private_data);
329
330     resp->lba = le_to_be_32((capacity / ATAPI_BLOCK_SIZE) - 1);
331     resp->block_len = le_to_be_32(ATAPI_BLOCK_SIZE);
332
333     atapi_setup_cmd_resp(ide, channel, sizeof(struct atapi_rd_capacity_resp));
334
335     return 0;
336 }
337
338 static int atapi_get_config(struct ide_internal * ide, struct ide_channel * channel) {
339     struct ide_drive * drive = get_selected_drive(channel);
340     struct atapi_config_cmd * cmd = (struct atapi_config_cmd *)(drive->data_buf);
341     uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
342     struct atapi_config_resp * resp = (struct atapi_config_resp *)(drive->data_buf);
343     int xfer_len = 8;
344
345     memset(resp, 0, sizeof(struct atapi_config_resp));
346
347     resp->data_len = le_to_be_32(xfer_len - 4);
348
349     if (alloc_len < xfer_len) {
350         xfer_len = alloc_len;
351     }
352     
353     V3_Print(VM_NONE, VCORE_NONE, "ATAPI Get config: xfer_len=%d\b", xfer_len);
354
355     atapi_setup_cmd_resp(ide, channel, xfer_len);
356     
357     return 0;
358 }
359
360
361 static int atapi_read_toc(struct ide_internal * ide, struct ide_channel * channel) {
362     struct ide_drive * drive = get_selected_drive(channel);
363     struct atapi_rd_toc_cmd * cmd = (struct atapi_rd_toc_cmd *)(drive->data_buf);
364     uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
365     struct atapi_rd_toc_resp * resp = (struct atapi_rd_toc_resp *)(drive->data_buf);
366
367     int xfer_len = 12;
368
369     memset(resp, 0, sizeof(struct atapi_rd_toc_resp));
370     
371     resp->data_len = le_to_be_16(10);
372     resp->first_track_num = 1;
373     resp->last_track_num = 1;
374
375     // we don't handle multi session
376     // we'll just treat it the same as single session
377     if ((cmd->format == 0) || (cmd->format == 1)) {
378         memset(&(resp->track_descs[0]), 0, 8);
379         
380         if (alloc_len < xfer_len) {
381             xfer_len = alloc_len;
382         }
383
384         atapi_setup_cmd_resp(ide, channel, xfer_len);
385     } else {
386         PrintError(VM_NONE, VCORE_NONE, "Unhandled Format (%d)\n", cmd->format);
387         return -1;
388     }
389
390     return 0;
391 }
392
393
394 static int atapi_mode_sense_cur_values(struct ide_internal * ide, struct ide_channel * channel, 
395                                        struct atapi_mode_sense_cmd * sense_cmd) {
396     struct ide_drive * drive = get_selected_drive(channel);
397     struct atapi_mode_sense_hdr * hdr = (struct atapi_mode_sense_hdr *)(drive->data_buf);
398     uint_t resp_len = sizeof(struct atapi_mode_sense_hdr);
399     uint16_t alloc_len = be_to_le_16(sense_cmd->alloc_len);
400     PrintDebug(VM_NONE, VCORE_NONE,"Page Code: %x\n", sense_cmd->page_code);
401     PrintDebug(VM_NONE, VCORE_NONE,"Alloc len: %d\n", alloc_len);
402
403     switch (sense_cmd->page_code) {
404
405         case 0x01: {    // error recovery
406             struct atapi_error_recovery * err = NULL;
407             err = (struct atapi_error_recovery *)(drive->data_buf + 
408                                                   sizeof(struct atapi_mode_sense_hdr));
409
410
411             memcpy(err, &(drive->cd_state.err_recovery), sizeof(struct atapi_error_recovery));
412
413             resp_len += sizeof(struct atapi_error_recovery);
414
415             PrintError(VM_NONE, VCORE_NONE,"mode sense (error recovery) resp_len=%d\n", resp_len);
416
417
418             hdr->mode_data_len = le_to_be_16(resp_len - 2);
419             
420             break;
421         }
422         case 0x2a: { // CDROM caps and mech. status
423
424             uint8_t * buf = drive->data_buf;
425
426
427
428             PrintError(VM_NONE, VCORE_NONE, "mode sense (caps/mechs v2) resp_len=%d\n", resp_len);
429
430             *((uint16_t *)buf) = le_to_be_16(28 + 6);
431             buf[2] = 0x70;
432             buf[3] = 0;
433             buf[4] = 0;
434             buf[5] = 0;
435             buf[6] = 0;
436             buf[7] = 0;
437
438             buf[8] = 0x2a;
439             buf[9] = 0x12;
440             buf[10] = 0x00;
441             buf[11] = 0x00;
442
443             /* Claim PLAY_AUDIO capability (0x01) since some Linux
444                code checks for this to automount media. */
445             buf[12] = 0x71;
446             buf[13] = 3 << 5;
447             buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
448
449             buf[6] |= 1 << 1;
450             buf[15] = 0x00;
451             *((uint16_t *)&(buf[16])) = le_to_be_16(706);
452             buf[18] = 0;
453             buf[19] = 2;
454             *((uint16_t *)&(buf[20])) = le_to_be_16(512);
455             *((uint16_t *)&(buf[22])) = le_to_be_16(706);
456             buf[24] = 0;
457             buf[25] = 0;
458             buf[26] = 0;
459             buf[27] = 0;
460
461             resp_len = 28;
462
463 #if 0
464             struct atapi_cdrom_caps * caps = NULL;
465             caps = (struct atapi_cdrom_caps *)(drive->data_buf + sizeof(struct atapi_mode_sense_hdr));
466             
467
468
469
470             memset(caps, 0, sizeof(struct atapi_cdrom_caps));
471
472             resp_len += sizeof(struct atapi_cdrom_caps);
473
474             hdr->mode_data_len = le_to_be_16(resp_len - 2);
475
476
477             PrintError(VM_NONE, VCORE_NONE, "mode sense (caps/mechs v2) resp_len=%d\n", resp_len);
478
479             caps->page_code = 0x2a;
480             caps->page_len = 0x12;
481             caps->mode2_form1 = 1;
482             caps->mode2_form2 = 1;
483             caps->multisession = 1;
484             caps->isrc = 1;
485             caps->upc = 1;
486
487             /* JRL TODO: These are dynamic caps */
488             caps->lock = 1;
489             caps->lock_state = 0;
490             caps->eject = 1;
491
492             caps->lmt = 1;
493             caps->obsolete1 = le_to_be_16(0x2c2);
494             caps->num_vols_supp = le_to_be_16(2);
495
496             caps->lun_buf_size = le_to_be_16(512);
497             caps->obsolete2 = le_to_be_16(0x2c2);
498
499 #endif
500
501             break;
502         }
503         case 0x0d:
504         case 0x0e:
505         case 0x3f:
506         default:
507             PrintError(VM_NONE, VCORE_NONE, "ATAPI: Mode sense Page Code not supported (%x)\n", sense_cmd->page_code);
508             atapi_cmd_error(ide, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
509             ide_raise_irq(ide, channel);
510             return 0;
511     }
512
513
514     // We do this after error checking, because its only valid if everything worked
515     //    memset(hdr, 0, sizeof(struct atapi_mode_sense_hdr));
516     // hdr->media_type_code = 0x70;
517
518     PrintDebug(VM_NONE, VCORE_NONE, "resp_len=%d\n", resp_len);
519
520     drive->transfer_length = (resp_len > alloc_len) ? alloc_len : resp_len;
521     drive->transfer_index = 0;
522     atapi_update_req_len(ide, channel, drive->transfer_length);
523
524     ide_raise_irq(ide, channel);
525
526     return 0;
527 }
528
529
530 static int atapi_mode_sense(struct ide_internal * ide, struct ide_channel * channel) {
531     struct ide_drive * drive = get_selected_drive(channel);
532     struct atapi_mode_sense_cmd * sense_cmd = (struct atapi_mode_sense_cmd *)(drive->data_buf);
533
534     switch (sense_cmd->page_ctrl) {
535         case 0x00: // Current values
536             return atapi_mode_sense_cur_values(ide, channel, sense_cmd);
537         case 0x01: // Changeable values
538         case 0x02: // default values
539         case 0x03: // saved values
540         default:
541             PrintError(VM_NONE, VCORE_NONE, "ATAPI: Mode sense mode not supported (%x)\n", sense_cmd->page_ctrl);
542             return -1;
543     }
544     return 0;
545 }
546
547
548
549 static int atapi_inquiry(struct ide_internal * ide, struct ide_channel * channel) {
550     struct ide_drive * drive = get_selected_drive(channel);
551     struct atapi_inquiry_cmd * inquiry_cmd = (struct atapi_inquiry_cmd *)(drive->data_buf);
552     uint16_t alloc_len = be_to_le_16(inquiry_cmd->alloc_len);
553     struct atapi_inquiry_resp * resp = (struct atapi_inquiry_resp *)(drive->data_buf);
554     int xfer_len = sizeof(struct atapi_inquiry_resp);
555     const char * vendor_id = "VTAB    ";
556     const char * product_id = "Turbo CD-ROM    ";
557     const char * product_rev = "1.0 ";
558
559     memset(resp, 0, sizeof(struct atapi_inquiry_resp));
560     
561     resp->dev_type = DEV_TYPE_CDROM;
562     resp->removable_media = 1;
563     resp->resp_data_fmt = 0x1;
564     resp->atapi_trans_ver = 0x2;
565     resp->additional_len = 31;
566
567     memcpy(resp->t10_vendor_id, vendor_id, strlen(vendor_id));
568     memcpy(resp->product_id, product_id, strlen(product_id));
569     memcpy(resp->product_rev, product_rev, strlen(product_rev));
570     
571     if (alloc_len < xfer_len) {
572         xfer_len = alloc_len;
573     }
574
575     atapi_setup_cmd_resp(ide, channel, xfer_len);
576
577     return 0;
578 }
579
580
581 static int atapi_mech_status(struct ide_internal * ide, struct ide_channel * channel) {
582     struct ide_drive * drive = get_selected_drive(channel);
583     struct atapi_mech_status_cmd * status_cmd = (struct atapi_mech_status_cmd *)(drive->data_buf);
584     uint16_t alloc_len = be_to_le_16(status_cmd->alloc_len);
585     struct atapi_mech_status_resp * resp = (struct atapi_mech_status_resp *)(drive->data_buf);
586     int xfer_len = sizeof(struct atapi_mech_status_resp);
587
588     memset(resp, 0, sizeof(struct atapi_mech_status_resp));
589
590     resp->lba = le_to_be_32(1);
591     resp->slot_table_len = le_to_be_16(0);
592     
593     if (alloc_len < xfer_len) {
594         xfer_len = alloc_len;
595     }
596
597     atapi_setup_cmd_resp(ide, channel, xfer_len);
598
599     return 0;
600 }
601
602
603 static int atapi_cmd_is_data_op(uint8_t cmd) {
604     switch (cmd) {
605         case 0x28: // read (10)
606         case 0xa8: // read (12)
607         case 0x2a: // write (10)
608         case 0xaa: // write (12)
609             return 1;
610         default:
611             return 0;
612     } 
613 }
614
615
616 static int atapi_handle_packet(struct guest_info * core, struct ide_internal * ide, struct ide_channel * channel) {
617    struct ide_drive * drive = get_selected_drive(channel);
618    uint8_t cmd = drive->data_buf[0];
619
620    PrintDebug(core->vm_info, core, "IDE: ATAPI Command %x\n", cmd);
621
622    drive->cd_state.atapi_cmd = cmd;
623
624    switch (cmd) {
625        case 0x00: // test unit ready
626            atapi_cmd_nop(ide, channel);
627
628            /* if drive not ready: 
629               atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
630            */
631            break;
632        case 0x03: // request sense
633            PrintError(core->vm_info, core, "IDE: Requesting Sense (0x3)\n");
634            atapi_req_sense(ide, channel);
635            break;
636
637        case 0x1e: // lock door
638            atapi_cmd_nop(ide, channel);
639            break;
640
641        case 0x28: // read(10)
642            if (atapi_read10(core, ide, channel) == -1) {
643                PrintError(core->vm_info, core, "IDE: Error in ATAPI read (%x)\n", cmd);
644                return -1;
645            }
646            break;
647
648        case 0x5a: // mode sense
649            if (atapi_mode_sense(ide, channel) == -1) {
650                PrintError(core->vm_info, core, "IDE: Error in ATAPI mode sense (%x)\n", cmd);
651                return -1;
652            }
653            break;
654
655
656        case 0x25: // read cdrom capacity
657            if (atapi_get_capacity(ide, channel) == -1) {
658                PrintError(core->vm_info, core, "IDE: Error getting CDROM capacity (%x)\n", cmd);
659                return -1;
660            }
661            break;
662
663
664        case 0x43: // read TOC
665            if (atapi_read_toc(ide, channel) == -1) {
666                PrintError(core->vm_info, core, "IDE: Error getting CDROM TOC (%x)\n", cmd);
667                return -1;
668            }
669            break;
670
671        case 0x46: // get configuration
672            if (atapi_get_config(ide, channel) == -1) {
673                PrintError(core->vm_info, core, "IDE: Error getting CDROM Configuration (%x)\n", cmd);
674                return -1;
675            }
676            break;
677
678
679        case 0x4a: // Get Status/event
680        case 0x51: // read disk info
681            // no-op to keep the Linux CD-ROM driver happy
682            PrintDebug(core->vm_info, core, "Error: Read disk info no-op to keep the Linux CD-ROM driver happy\n");
683            atapi_cmd_error(ide, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
684            ide_raise_irq(ide, channel);
685            break;
686
687        case 0x12: // inquiry
688            if (atapi_inquiry(ide, channel) == -1) {
689                PrintError(core->vm_info, core, "IDE: Error in ATAPI inquiry (%x)\n", cmd);
690                return -1;
691            }
692            break;
693
694        case 0xbd: // mechanism status 
695            if (atapi_mech_status(ide, channel) == -1) {
696                PrintError(core->vm_info, core, "IDE: error in ATAPI Mechanism status query (%x)\n", cmd);
697                return -1;
698            }
699            break;
700
701
702        case 0xa8: // read(12)
703
704
705        case 0x1b: // start/stop drive
706          atapi_cmd_nop(ide,channel);
707          break;
708
709        case 0xbe: // read cd
710
711
712
713        case 0x2b: // seek
714
715        case 0x42: // read sub-channel
716
717
718            
719        case 0x55: // mode select
720        case 0xa6: // load/unload cd
721        case 0x4b: // pause/resume
722        case 0x45: // play audio
723        case 0x47: // play audio msf
724        case 0xbc: // play cd
725        case 0xb9: // read cd msf
726        case 0x44: // read header
727        case 0xba: // scan
728        case 0xbb: // set cd speed
729        case 0x4e: // stop play/scan
730
731        default:
732            PrintError(core->vm_info, core, "Unhandled ATAPI command %x\n", cmd);
733            atapi_cmd_error(ide, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
734            ide_raise_irq(ide, channel);
735            return -1;
736    }
737    
738    return 0;
739 }
740
741
742 static void atapi_identify_device(struct ide_drive * drive) {
743     struct ide_drive_id * drive_id = (struct ide_drive_id *)(drive->data_buf);
744     const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0";
745     const char* firmware = "ALPHA1  ";
746
747     drive->transfer_length = 512;
748     drive->transfer_index = 0;
749
750
751     memset(drive_id->buf, 0, sizeof(drive_id->buf));
752
753     drive_id->fixed_drive = 1;
754     drive_id->removable_media = 1;
755
756     // Black magic...
757     drive_id->disk_speed1 = 1;
758     drive_id->disk_speed3 = 1;
759
760     drive_id->cdrom_flag = 1;
761
762     // These buffers do not contain a terminating "\0"
763     memcpy(drive_id->serial_num, serial_number, strlen(serial_number));
764     memcpy(drive_id->firmware_rev, firmware, strlen(firmware));
765     memcpy(drive_id->model_num, drive->model, 40);
766
767     // 32 bits access
768     drive_id->dword_io = 1;
769
770     // enable DMA access
771     /* Disabled until command packet DMA is fixed */
772     drive_id->dma_enable = 1;
773
774     // enable LBA access
775     drive_id->lba_enable = 1;
776     
777     drive_id->rw_multiples = 0x80ff;
778
779     // words 64-70, 54-58 valid
780     /* Disabled until command packet DMA is fixed */
781         drive_id->field_valid = 0x0007; // DMA + pkg cmd valid
782
783     // copied from CFA540A
784     /* Disabled until command packet DMA is fixed */
785      drive_id->buf[63] = 0x0103; // variable (DMA stuff)
786        
787
788     /* uncommented to disable dma(?) */
789      // drive_id->buf[64] = 0x0001; // PIO
790
791
792     drive_id->buf[65] = 0x00b4;
793     drive_id->buf[66] = 0x00b4;
794     drive_id->buf[67] = 0x012c;
795     drive_id->buf[68] = 0x00b4;
796
797     drive_id->buf[71] = 30; // faked
798     drive_id->buf[72] = 30; // faked
799
800     //    drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4
801     drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6
802
803     /* Disabled until command packet DMA is fixed */
804     drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported;
805 }
806
807 #endif