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.


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