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.


added ATAPI inquiry command
[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_handle_packet(struct vm_device * dev, struct ide_channel * channel) {
440    struct ide_drive * drive = get_selected_drive(channel);
441    uint8_t cmd = drive->data_buf[0];
442
443    PrintDebug("IDE: ATAPI Command %x\n", cmd);
444
445    drive->cd_state.atapi_cmd = cmd;
446
447    switch (cmd) {
448        case 0x00: // test unit ready
449            atapi_cmd_nop(dev, channel);
450
451            /* if drive not ready: 
452               atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
453            */
454            break;
455        case 0x03: // request sense
456            atapi_req_sense(dev, channel);
457            break;
458
459        case 0x28: // read(10)
460            if (atapi_read10(dev, channel) == -1) {
461                PrintError("IDE: Error in ATAPI read (%x)\n", cmd);
462                return -1;
463            }
464            break;
465
466        case 0x5a: // mode sense
467            if (atapi_mode_sense(dev, channel) == -1) {
468                PrintError("IDE: Error in ATAPI mode sense (%x)\n", cmd);
469                return -1;
470            }
471            break;
472
473
474        case 0x25: // read cdrom capacity
475            if (atapi_get_capacity(dev, channel) == -1) {
476                PrintError("IDE: Error getting CDROM capacity (%x)\n", cmd);
477                return -1;
478            }
479            break;
480
481
482        case 0x43: // read TOC
483            if (atapi_read_toc(dev, channel) == -1) {
484                PrintError("IDE: Error getting CDROM TOC (%x)\n", cmd);
485                return -1;
486            }
487            break;
488
489        case 0x46: // get configuration
490            if (atapi_get_config(dev, channel) == -1) {
491                PrintError("IDE: Error getting CDROM Configuration (%x)\n", cmd);
492                return -1;
493            }
494            break;
495
496        case 0x51: // read disk info
497            // no-op to keep the Linux CD-ROM driver happy
498            PrintDebug("Error: Read disk info no-op to keep the Linux CD-ROM driver happy\n");
499            atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
500            ide_raise_irq(dev, channel);
501            break;
502
503        case 0x12: // inquiry
504            if (atapi_inquiry(dev, channel) == -1) {
505                PrintError("IDE: Error in ATAPI inquiry (%x)\n", cmd);
506                return -1;
507            }
508            break;
509
510        case 0xa8: // read(12)
511
512
513        case 0x1b: // start/stop drive
514        case 0xbd: // mechanism status 
515
516        case 0xbe: // read cd
517
518
519
520        case 0x2b: // seek
521        case 0x1e: // lock door
522        case 0x42: // read sub-channel
523
524
525            
526        case 0x55: // mode select
527        case 0xa6: // load/unload cd
528        case 0x4b: // pause/resume
529        case 0x45: // play audio
530        case 0x47: // play audio msf
531        case 0xbc: // play cd
532        case 0xb9: // read cd msf
533        case 0x44: // read header
534        case 0xba: // scan
535        case 0xbb: // set cd speed
536        case 0x4e: // stop play/scan
537  
538        case 0x4a: // ???
539        default:
540            PrintError("Unhandled ATAPI command %x\n", cmd);
541            atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
542            ide_raise_irq(dev, channel);
543            return -1;
544    }
545    
546    return 0;
547 }
548
549
550 static void atapi_identify_device(struct ide_drive * drive) {
551     struct ide_drive_id * drive_id = (struct ide_drive_id *)(drive->data_buf);
552     const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0";
553     const char* firmware = "ALPHA1  ";
554
555     drive->transfer_length = 512;
556     drive->transfer_index = 0;
557
558
559     memset(drive_id->buf, 0, sizeof(drive_id->buf));
560
561     drive_id->fixed_drive = 1;
562     drive_id->removable_media = 1;
563
564     // Black magic...
565     drive_id->disk_speed1 = 1;
566     drive_id->disk_speed3 = 1;
567
568     drive_id->cdrom_flag = 1;
569
570     // These buffers do not contain a terminating "\0"
571     memcpy(drive_id->serial_num, serial_number, strlen(serial_number));
572     memcpy(drive_id->firmware_rev, firmware, strlen(firmware));
573     memcpy(drive_id->model_num, drive->model, 40);
574
575     // 32 bits access
576     drive_id->dword_io = 1;
577
578     // enable DMA access
579     drive_id->dma_enable = 1;
580
581     // enable LBA access
582     drive_id->lba_enable = 1;
583     
584     drive_id->rw_multiples = 0x80ff;
585
586     // words 64-70, 54-58 valid
587     drive_id->field_valid = 0x0007; // DMA + pkg cmd valid
588
589     // copied from CFA540A
590     drive_id->buf[63] = 0x0103; // variable (DMA stuff)
591     //drive_id->buf[63] = 0x0000; // variable (DMA stuff)
592     
593     //    drive_id->buf[64] = 0x0001; // PIO
594     drive_id->buf[65] = 0x00b4;
595     drive_id->buf[66] = 0x00b4;
596     drive_id->buf[67] = 0x012c;
597     drive_id->buf[68] = 0x00b4;
598
599     drive_id->buf[71] = 30; // faked
600     drive_id->buf[72] = 30; // faked
601
602     //    drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4
603     drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6
604
605     drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported;
606 }