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.


27bed29013c38b629e9376f839022c63013fac07
[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 #define ATAPI_PACKET_SIZE 12
21
22 #include "atapi-types.h"
23
24
25 /* ATAPI sucks...
26  * The OS will write to the cylinder register the number of bytes it wants to read 
27  * however the device can change that value 
28  * 
29  */
30 static int atapi_update_req_len(struct vm_device * dev, struct ide_channel * channel, uint_t xfer_len) {
31     struct ide_drive * drive = get_selected_drive(channel);
32
33     //   PrintDebug("Updating request length (pre=%d)\n", drive->req_len);
34
35     if (drive->req_len == 0) {
36         PrintError("ATAPI Error: request of length 0\n");
37         return -1;
38     }
39
40
41     channel->status.busy = 0;
42     channel->status.data_req = 1;
43     channel->status.error = 0;
44
45     drive->irq_flags.io_dir = 1;
46     drive->irq_flags.c_d = 0;
47
48     // make count even
49     if (drive->req_len % 2) {
50         drive->req_len -= 1;
51     }
52
53     // if the device can't return as much as the OS requested
54     if (drive->req_len > xfer_len) {
55         drive->req_len = xfer_len;
56     }
57
58     //    PrintDebug("Updating request length (post=%d)\n", drive->req_len);
59
60     return 0;
61 }
62
63
64
65 // This is for simple commands that don't need to sanity check the req_len
66 static void atapi_setup_cmd_resp(struct vm_device * dev, struct ide_channel * channel, uint_t xfer_len) {
67     struct ide_drive * drive = get_selected_drive(channel);
68
69     drive->transfer_length = xfer_len;
70     drive->transfer_index = 0;
71     drive->req_len = drive->transfer_length;
72
73     drive->irq_flags.io_dir = 1;
74     drive->irq_flags.c_d = 0;
75
76     channel->status.busy = 0;
77     channel->status.data_req = 1;
78     channel->status.error = 0;
79
80     ide_raise_irq(dev, channel);
81 }
82
83 static void atapi_cmd_error(struct vm_device * dev, struct ide_channel * channel, 
84                      atapi_sense_key_t  sense_key, atapi_add_sense_code_t asc) {
85     struct ide_drive * drive = get_selected_drive(channel);
86
87     // overload error register with ATAPI value
88     channel->error_reg.val = sense_key << 4;
89     
90     channel->status.busy = 0;
91     channel->status.ready = 1;
92     channel->status.write_fault = 0;
93     channel->status.data_req = 0;
94     channel->status.error = 1;
95   
96     drive->cd_state.sense.header = 0xf0;
97     drive->cd_state.sense.rsvd1 = 0x00;
98     drive->cd_state.sense.read_len = 0x0a;
99     drive->cd_state.sense.sense_key = sense_key;
100     drive->cd_state.sense.asc = asc;
101
102
103     drive->irq_flags.io_dir = 1;
104     drive->irq_flags.c_d = 1;
105     drive->irq_flags.rel = 0;
106
107     ide_raise_irq(dev, channel);
108 }
109
110
111 static void atapi_cmd_nop(struct vm_device * dev, struct ide_channel * channel) {
112     struct ide_drive * drive = get_selected_drive(channel);
113
114     channel->status.busy = 0;
115     channel->status.ready = 1;
116     channel->status.data_req = 0;
117     channel->status.error = 0;
118
119     drive->irq_flags.io_dir = 1;
120     drive->irq_flags.c_d = 1;
121     drive->irq_flags.rel = 0;
122
123     ide_raise_irq(dev, channel);
124 }
125
126
127
128 static int atapi_read_chunk(struct vm_device * dev, struct ide_channel * channel) {
129     struct ide_drive * drive = get_selected_drive(channel);
130
131     int ret = drive->cd_ops->read(drive->data_buf, 1, drive->current_lba, drive->private_data);
132     
133     if (ret == -1) {
134         PrintError("IDE: Error reading CD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba));
135         return -1;
136     }
137
138     return 0;
139 }
140
141
142 static int atapi_update_data_buf(struct vm_device * dev, struct ide_channel * channel) {
143     struct ide_drive * drive = get_selected_drive(channel);    
144     
145     switch (drive->cd_state.atapi_cmd) {
146         case 0x28: // read(10)
147         case 0xa8: // read(12)
148
149             // Update lba address to point to next block
150             drive->current_lba++;
151
152             // read the next block
153             return atapi_read_chunk(dev, channel);
154
155         default:
156             PrintError("Unhandled ATAPI command in update buffer %x\n", drive->cd_state.atapi_cmd);
157             return -1;
158     }
159
160     return 0;
161 }
162
163 static int atapi_read10(struct vm_device * dev, struct ide_channel * channel) {
164     struct ide_drive * drive = get_selected_drive(channel);
165     struct atapi_read10_cmd * cmd = (struct atapi_read10_cmd *)(drive->data_buf);
166     uint32_t lba =  be_to_le_32(cmd->lba);
167     uint16_t xfer_len = be_to_le_16(cmd->xfer_len);
168
169     PrintDebug("READ10: XferLen=%d\n", xfer_len);
170
171     /* Check if cd is ready
172      * if not: atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
173      */
174     
175     if (xfer_len == 0) {
176         atapi_cmd_nop(dev, channel);
177         return 0;
178     }
179     
180     if (lba + xfer_len > drive->cd_ops->get_capacity(drive->private_data)) {
181         PrintError("IDE: xfer len exceeded capacity (lba=%d) (xfer_len=%d) (ReadEnd=%d) (capacity=%d)\n", 
182                    lba, xfer_len, lba + xfer_len, 
183                    drive->cd_ops->get_capacity(drive->private_data));
184         atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_LOG_BLK_OOR);
185         ide_raise_irq(dev, channel);
186         return 0;
187     }
188         
189     //    PrintDebug("Reading %d blocks from LBA 0x%x\n", xfer_len, lba);
190     
191     drive->current_lba = lba;
192         
193     // Update the request length value in the cylinder registers
194     drive->transfer_length = xfer_len * ATAPI_BLOCK_SIZE;
195     drive->transfer_index = 0;  
196
197     if (channel->features.dma) {
198
199         if (channel->dma_status.active == 1) {
200             if (dma_read(dev, channel) == -1) {
201                 PrintError("Error in DMA read for CD Read10 command\n");
202                 return -1;
203             }
204         }
205         return 0;
206     }
207
208     if (atapi_read_chunk(dev, channel) == -1) {
209         PrintError("IDE: Could not read initial chunk from CD\n");
210         return -1;
211     }
212         
213     // Length of ATAPI buffer sits in cylinder registers
214     // This is weird... The host sets this value to say what it would like to transfer, 
215     // if it is larger than the correct size, the device shrinks it to the correct size
216     if (atapi_update_req_len(dev, channel, ATAPI_BLOCK_SIZE) == -1) {
217         PrintError("Could not update initial request length\n");
218         return -1;
219     }
220     
221     ide_raise_irq(dev, channel);
222
223     return 0;
224 }
225
226
227
228 static void atapi_req_sense(struct vm_device * dev, struct ide_channel * channel) {
229     struct ide_drive * drive = get_selected_drive(channel);
230
231     memcpy(drive->data_buf, drive->cd_state.sense.buf, sizeof(drive->cd_state.sense.buf));
232    
233     atapi_setup_cmd_resp(dev, channel, 18);
234 }
235
236
237
238 static int atapi_get_capacity(struct vm_device * dev, struct ide_channel * channel) {
239     struct ide_drive * drive = get_selected_drive(channel);
240     struct atapi_rd_capacity_resp * resp = (struct atapi_rd_capacity_resp *)(drive->data_buf);
241     uint32_t capacity = drive->cd_ops->get_capacity(drive->private_data);
242
243     resp->lba = le_to_be_32(capacity);
244     resp->block_len = le_to_be_32(ATAPI_BLOCK_SIZE);
245
246     atapi_setup_cmd_resp(dev, channel, sizeof(struct atapi_rd_capacity_resp));
247
248     return 0;
249 }
250
251 static int atapi_get_config(struct vm_device * dev, struct ide_channel * channel) {
252     struct ide_drive * drive = get_selected_drive(channel);
253     struct atapi_config_cmd * cmd = (struct atapi_config_cmd *)(drive->data_buf);
254     uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
255     struct atapi_config_resp * resp = (struct atapi_config_resp *)(drive->data_buf);
256     int xfer_len = 8;
257
258     memset(resp, 0, sizeof(struct atapi_config_resp));
259
260     resp->data_len = le_to_be_32(xfer_len - 4);
261
262     if (alloc_len < xfer_len) {
263         xfer_len = alloc_len;
264     }
265     
266     atapi_setup_cmd_resp(dev, channel, xfer_len);
267     
268     return 0;
269 }
270
271
272 static int atapi_read_toc(struct vm_device * dev, struct ide_channel * channel) {
273     struct ide_drive * drive = get_selected_drive(channel);
274     struct atapi_rd_toc_cmd * cmd = (struct atapi_rd_toc_cmd *)(drive->data_buf);
275     uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
276     struct atapi_rd_toc_resp * resp = (struct atapi_rd_toc_resp *)(drive->data_buf);
277
278     int xfer_len = 12;
279
280     memset(resp, 0, sizeof(struct atapi_rd_toc_resp));
281     
282     resp->data_len = le_to_be_16(10);
283     resp->first_track_num = 1;
284     resp->last_track_num = 1;
285
286     // we don't handle multi session
287     // we'll just treat it the same as single session
288     if ((cmd->format == 0) || (cmd->format == 1)) {
289         memset(&(resp->track_descs[0]), 0, 8);
290         
291         if (alloc_len < xfer_len) {
292             xfer_len = alloc_len;
293         }
294
295         atapi_setup_cmd_resp(dev, channel, xfer_len);
296     } else {
297         PrintError("Unhandled Format (%d)\n", cmd->format);
298         return -1;
299     }
300
301     return 0;
302 }
303
304
305 static int atapi_mode_sense_cur_values(struct vm_device * dev, struct ide_channel * channel, 
306                                        struct atapi_mode_sense_cmd * sense_cmd) {
307     struct ide_drive * drive = get_selected_drive(channel);
308     struct atapi_mode_sense_hdr * hdr = (struct atapi_mode_sense_hdr *)(drive->data_buf);
309     uint_t resp_len = sizeof(struct atapi_mode_sense_hdr);
310     uint16_t alloc_len = be_to_le_16(sense_cmd->alloc_len);
311     PrintDebug("Page Code: %x\n", sense_cmd->page_code);
312     PrintDebug("Alloc len: %d\n", alloc_len);
313
314     switch (sense_cmd->page_code) {
315
316         case 0x01: {    // error recovery
317             struct atapi_error_recovery * err = NULL;
318             err = (struct atapi_error_recovery *)(drive->data_buf + 
319                                                   sizeof(struct atapi_mode_sense_hdr));
320
321             memcpy(err, &(drive->cd_state.err_recovery), sizeof(struct atapi_error_recovery));
322
323             resp_len += sizeof(struct atapi_error_recovery);
324
325             hdr->mode_data_len = le_to_be_16(resp_len - 2);
326             
327             break;
328         }
329         case 0x2a: { // CDROM caps and mech. status
330             struct atapi_cdrom_caps * caps = NULL;
331             caps = (struct atapi_cdrom_caps *)(drive->data_buf + sizeof(struct atapi_mode_sense_hdr));
332             
333
334             memset(caps, 0, sizeof(struct atapi_cdrom_caps));
335
336             resp_len += sizeof(struct atapi_cdrom_caps);
337
338             hdr->mode_data_len = le_to_be_16(resp_len - 2);
339
340             caps->page_code = 0x2a;
341             caps->page_len = 0x12;
342             caps->mode2_form1 = 1;
343             caps->mode2_form2 = 1;
344             caps->multisession = 1;
345             caps->isrc = 1;
346             caps->upc = 1;
347
348             /* JRL TODO: These are dynamic caps */
349             caps->lock = 1;
350             caps->lock_state = 0;
351             caps->eject = 1;
352
353             caps->lmt = 1;
354             caps->obsolete1 = le_to_be_16(0x2c2);
355             caps->num_vols_supp = le_to_be_16(2);
356
357             caps->lun_buf_size = le_to_be_16(512);
358             caps->obsolete2 = le_to_be_16(0x2c2);
359
360             break;
361         }
362         case 0x0d:
363         case 0x0e:
364         case 0x3f:
365         default:
366             PrintError("ATAPI: Mode sense Page Code not supported (%x)\n", sense_cmd->page_code);
367             atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
368             ide_raise_irq(dev, channel);
369             return 0;
370     }
371
372
373     // We do this after error checking, because its only valid if everything worked
374     memset(hdr, 0, sizeof(struct atapi_mode_sense_hdr));
375     hdr->media_type_code = 0x70;
376
377     PrintDebug("resp_len=%d\n", resp_len);
378
379     drive->transfer_length = (resp_len > alloc_len) ? alloc_len : resp_len;
380     drive->transfer_index = 0;
381     atapi_update_req_len(dev, channel, drive->transfer_length);
382
383     ide_raise_irq(dev, channel);
384
385     return 0;
386 }
387
388
389 static int atapi_mode_sense(struct vm_device * dev, struct ide_channel * channel) {
390     struct ide_drive * drive = get_selected_drive(channel);
391     struct atapi_mode_sense_cmd * sense_cmd = (struct atapi_mode_sense_cmd *)(drive->data_buf);
392
393     switch (sense_cmd->page_ctrl) {
394         case 0x00: // Current values
395             return atapi_mode_sense_cur_values(dev, channel, sense_cmd);
396         case 0x01: // Changeable values
397         case 0x02: // default values
398         case 0x03: // saved values
399         default:
400             PrintError("ATAPI: Mode sense mode not supported (%x)\n", sense_cmd->page_ctrl);
401             return -1;
402     }
403     return 0;
404 }
405
406
407 static int atapi_inquiry(struct vm_device * dev, struct ide_channel * channel) {
408     struct ide_drive * drive = get_selected_drive(channel);
409     struct atapi_inquiry_cmd * inquiry_cmd = (struct atapi_inquiry_cmd *)(drive->data_buf);
410     uint16_t alloc_len = be_to_le_16(inquiry_cmd->alloc_len);
411     struct atapi_inquiry_resp * resp = (struct atapi_inquiry_resp *)(drive->data_buf);
412     int xfer_len = sizeof(struct atapi_inquiry_resp);
413     const char * vendor_id = "VTAB    ";
414     const char * product_id = "Turbo CD-ROM    ";
415     const char * product_rev = "1.0 ";
416
417     memset(resp, 0, sizeof(struct atapi_inquiry_resp));
418     
419     resp->dev_type = DEV_TYPE_CDROM;
420     resp->removable_media = 1;
421     resp->resp_data_fmt = 0x1;
422     resp->atapi_trans_ver = 0x2;
423     resp->additional_len = 31;
424
425     memcpy(resp->t10_vendor_id, vendor_id, strlen(vendor_id));
426     memcpy(resp->product_id, product_id, strlen(product_id));
427     memcpy(resp->product_rev, product_rev, strlen(product_rev));
428     
429     if (alloc_len < xfer_len) {
430         xfer_len = alloc_len;
431     }
432
433     atapi_setup_cmd_resp(dev, channel, xfer_len);
434
435     return 0;
436 }
437
438
439 static int atapi_cmd_is_data_op(uint8_t cmd) {
440     switch (cmd) {
441         case 0x28: // read (10)
442         case 0xa8: // read (12)
443         case 0x2a: // write (10)
444         case 0xaa: // write (12)
445             return 1;
446         default:
447             return 0;
448     } 
449 }
450
451
452 static int atapi_handle_packet(struct vm_device * dev, struct ide_channel * channel) {
453    struct ide_drive * drive = get_selected_drive(channel);
454    uint8_t cmd = drive->data_buf[0];
455
456    PrintDebug("IDE: ATAPI Command %x\n", cmd);
457
458    drive->cd_state.atapi_cmd = cmd;
459
460    switch (cmd) {
461        case 0x00: // test unit ready
462            atapi_cmd_nop(dev, channel);
463
464            /* if drive not ready: 
465               atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
466            */
467            break;
468        case 0x03: // request sense
469            atapi_req_sense(dev, channel);
470            break;
471
472        case 0x1e: // lock door
473            atapi_cmd_nop(dev, channel);
474            break;
475
476        case 0x28: // read(10)
477            if (atapi_read10(dev, channel) == -1) {
478                PrintError("IDE: Error in ATAPI read (%x)\n", cmd);
479                return -1;
480            }
481            break;
482
483        case 0x5a: // mode sense
484            if (atapi_mode_sense(dev, channel) == -1) {
485                PrintError("IDE: Error in ATAPI mode sense (%x)\n", cmd);
486                return -1;
487            }
488            break;
489
490
491        case 0x25: // read cdrom capacity
492            if (atapi_get_capacity(dev, channel) == -1) {
493                PrintError("IDE: Error getting CDROM capacity (%x)\n", cmd);
494                return -1;
495            }
496            break;
497
498
499        case 0x43: // read TOC
500            if (atapi_read_toc(dev, channel) == -1) {
501                PrintError("IDE: Error getting CDROM TOC (%x)\n", cmd);
502                return -1;
503            }
504            break;
505
506        case 0x46: // get configuration
507            if (atapi_get_config(dev, channel) == -1) {
508                PrintError("IDE: Error getting CDROM Configuration (%x)\n", cmd);
509                return -1;
510            }
511            break;
512
513        case 0x51: // read disk info
514            // no-op to keep the Linux CD-ROM driver happy
515            PrintDebug("Error: Read disk info no-op to keep the Linux CD-ROM driver happy\n");
516            atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
517            ide_raise_irq(dev, channel);
518            break;
519
520        case 0x12: // inquiry
521            if (atapi_inquiry(dev, channel) == -1) {
522                PrintError("IDE: Error in ATAPI inquiry (%x)\n", cmd);
523                return -1;
524            }
525            break;
526
527        case 0xa8: // read(12)
528
529
530        case 0x1b: // start/stop drive
531        case 0xbd: // mechanism status 
532
533        case 0xbe: // read cd
534
535
536
537        case 0x2b: // seek
538
539        case 0x42: // read sub-channel
540
541
542            
543        case 0x55: // mode select
544        case 0xa6: // load/unload cd
545        case 0x4b: // pause/resume
546        case 0x45: // play audio
547        case 0x47: // play audio msf
548        case 0xbc: // play cd
549        case 0xb9: // read cd msf
550        case 0x44: // read header
551        case 0xba: // scan
552        case 0xbb: // set cd speed
553        case 0x4e: // stop play/scan
554  
555        case 0x4a: // ???
556        default:
557            PrintError("Unhandled ATAPI command %x\n", cmd);
558            atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
559            ide_raise_irq(dev, channel);
560            return -1;
561    }
562    
563    return 0;
564 }
565
566
567 static void atapi_identify_device(struct ide_drive * drive) {
568     struct ide_drive_id * drive_id = (struct ide_drive_id *)(drive->data_buf);
569     const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0";
570     const char* firmware = "ALPHA1  ";
571
572     drive->transfer_length = 512;
573     drive->transfer_index = 0;
574
575
576     memset(drive_id->buf, 0, sizeof(drive_id->buf));
577
578     drive_id->fixed_drive = 1;
579     drive_id->removable_media = 1;
580
581     // Black magic...
582     drive_id->disk_speed1 = 1;
583     drive_id->disk_speed3 = 1;
584
585     drive_id->cdrom_flag = 1;
586
587     // These buffers do not contain a terminating "\0"
588     memcpy(drive_id->serial_num, serial_number, strlen(serial_number));
589     memcpy(drive_id->firmware_rev, firmware, strlen(firmware));
590     memcpy(drive_id->model_num, drive->model, 40);
591
592     // 32 bits access
593     drive_id->dword_io = 1;
594
595     // enable DMA access
596     drive_id->dma_enable = 1;
597
598     // enable LBA access
599     drive_id->lba_enable = 1;
600     
601     drive_id->rw_multiples = 0x80ff;
602
603     // words 64-70, 54-58 valid
604     drive_id->field_valid = 0x0007; // DMA + pkg cmd valid
605
606     // copied from CFA540A
607     drive_id->buf[63] = 0x0103; // variable (DMA stuff)
608     //drive_id->buf[63] = 0x0000; // variable (DMA stuff)
609     
610     //    drive_id->buf[64] = 0x0001; // PIO
611     drive_id->buf[65] = 0x00b4;
612     drive_id->buf[66] = 0x00b4;
613     drive_id->buf[67] = 0x012c;
614     drive_id->buf[68] = 0x00b4;
615
616     drive_id->buf[71] = 30; // faked
617     drive_id->buf[72] = 30; // faked
618
619     //    drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4
620     drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6
621
622     drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported;
623 }