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.


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