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.


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