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.


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