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.


updates to ATAPI packet command support
[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
237 static int atapi_read_toc(struct vm_device * dev, struct ide_channel * channel) {
238     struct ide_drive * drive = get_selected_drive(channel);
239     struct atapi_rd_toc_cmd * cmd = (struct atapi_rd_toc_cmd *)(drive->data_buf);
240     uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
241     
242
243     struct atapi_rd_toc_resp * resp = (struct atapi_rd_toc_resp *)(drive->data_buf);
244
245     resp->data_len = 10;
246
247     return -1;
248
249 }
250
251
252 static int atapi_mode_sense_cur_values(struct vm_device * dev, struct ide_channel * channel, 
253                                        struct atapi_mode_sense_cmd * sense_cmd) {
254     struct ide_drive * drive = get_selected_drive(channel);
255     struct atapi_mode_sense_hdr * hdr = (struct atapi_mode_sense_hdr *)(drive->data_buf);
256     uint_t resp_len = sizeof(struct atapi_mode_sense_hdr);
257     uint16_t alloc_len = be_to_le_16(sense_cmd->alloc_len);
258     PrintDebug("Page Code: %x\n", sense_cmd->page_code);
259     PrintDebug("Alloc len: %d\n", alloc_len);
260
261     switch (sense_cmd->page_code) {
262
263         case 0x01: {    // error recovery
264             struct atapi_error_recovery * err = NULL;
265             err = (struct atapi_error_recovery *)(drive->data_buf + 
266                                                   sizeof(struct atapi_mode_sense_hdr));
267
268             memcpy(err, &(drive->cd_state.err_recovery), sizeof(struct atapi_error_recovery));
269
270             resp_len += sizeof(struct atapi_error_recovery);
271
272             hdr->mode_data_len = le_to_be_16(resp_len - 2);
273             
274             break;
275         }
276         case 0x2a: { // CDROM caps and mech. status
277             struct atapi_cdrom_caps * caps = NULL;
278             caps = (struct atapi_cdrom_caps *)(drive->data_buf + sizeof(struct atapi_mode_sense_hdr));
279             
280
281             memset(caps, 0, sizeof(struct atapi_cdrom_caps));
282
283             resp_len += sizeof(struct atapi_cdrom_caps);
284
285             hdr->mode_data_len = le_to_be_16(resp_len - 2);
286
287             caps->page_code = 0x2a;
288             caps->page_len = 0x12;
289             caps->mode2_form1 = 1;
290             caps->mode2_form2 = 1;
291             caps->multisession = 1;
292             caps->isrc = 1;
293             caps->upc = 1;
294
295             /* JRL TODO: These are dynamic caps */
296             caps->lock = 1;
297             caps->lock_state = 0;
298             caps->eject = 1;
299
300             caps->lmt = 1;
301             caps->obsolete1 = le_to_be_16(0x2c2);
302             caps->num_vols_supp = le_to_be_16(2);
303
304             caps->lun_buf_size = le_to_be_16(512);
305             caps->obsolete2 = le_to_be_16(0x2c2);
306
307             break;
308         }
309         case 0x0d:
310         case 0x0e:
311         case 0x3f:
312         default:
313             PrintError("ATAPI: Mode sense Page Code not supported (%x)\n", sense_cmd->page_code);
314             atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
315             ide_raise_irq(dev, channel);
316             return 0;
317     }
318
319
320     // We do this after error checking, because its only valid if everything worked
321     memset(hdr, 0, sizeof(struct atapi_mode_sense_hdr));
322     hdr->media_type_code = 0x70;
323
324     PrintDebug("resp_len=%d\n", resp_len);
325
326     drive->transfer_length = (resp_len > alloc_len) ? alloc_len : resp_len;
327     drive->transfer_index = 0;
328     atapi_update_req_len(dev, channel, drive->transfer_length);
329
330     ide_raise_irq(dev, channel);
331
332     return 0;
333 }
334
335
336 static int atapi_mode_sense(struct vm_device * dev, struct ide_channel * channel) {
337     struct ide_drive * drive = get_selected_drive(channel);
338     struct atapi_mode_sense_cmd * sense_cmd = (struct atapi_mode_sense_cmd *)(drive->data_buf);
339
340     switch (sense_cmd->page_ctrl) {
341         case 0x00: // Current values
342             return atapi_mode_sense_cur_values(dev, channel, sense_cmd);
343         case 0x01: // Changeable values
344         case 0x02: // default values
345         case 0x03: // saved values
346         default:
347             PrintError("ATAPI: Mode sense mode not supported (%x)\n", sense_cmd->page_ctrl);
348             return -1;
349     }
350     return 0;
351 }
352
353
354 static int atapi_handle_packet(struct vm_device * dev, struct ide_channel * channel) {
355    struct ide_drive * drive = get_selected_drive(channel);
356    uint8_t cmd = drive->data_buf[0];
357
358    PrintDebug("IDE: ATAPI Command %x\n", cmd);
359
360    drive->cd_state.atapi_cmd = cmd;
361
362    switch (cmd) {
363        case 0x00: // test unit ready
364            atapi_cmd_nop(dev, channel);
365
366            /* if drive not ready: 
367               atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
368            */
369            break;
370        case 0x03: // request sense
371            atapi_req_sense(dev, channel);
372            break;
373
374        case 0x28: // read(10)
375            if (atapi_read10(dev, channel) == -1) {
376                PrintError("IDE: Error in ATAPI read (%x)\n", cmd);
377                return -1;
378            }
379            break;
380
381        case 0x5a: // mode sense
382            if (atapi_mode_sense(dev, channel) == -1) {
383                PrintError("IDE: Error in ATAPI mode sense (%x)\n", cmd);
384                return -1;
385            }
386            break;
387
388
389        case 0x25: // read cdrom capacity
390            if (atapi_get_capacity(dev, channel) == -1) {
391                PrintError("IDE: Error getting CDROM capacity (%x)\n", cmd);
392                return -1;
393            }
394            break;
395
396
397        case 0x43: // read TOC
398            if (atapi_read_toc(dev, channel) == -1) {
399                PrintError("IDE: Error getting CDROM TOC (%x)\n", cmd);
400                return -1;
401            }
402            break;
403
404        case 0xa8: // read(12)
405
406
407        case 0x1b: // start/stop drive
408        case 0xbd: // mechanism status 
409        case 0x12: // inquiry
410
411        case 0xbe: // read cd
412
413
414
415        case 0x2b: // seek
416        case 0x1e: // lock door
417        case 0x42: // read sub-channel
418        case 0x51: // read disk info
419
420            
421        case 0x55: // mode select
422        case 0xa6: // load/unload cd
423        case 0x4b: // pause/resume
424        case 0x45: // play audio
425        case 0x47: // play audio msf
426        case 0xbc: // play cd
427        case 0xb9: // read cd msf
428        case 0x44: // read header
429        case 0xba: // scan
430        case 0xbb: // set cd speed
431        case 0x4e: // stop play/scan
432        case 0x46: // ???
433        case 0x4a: // ???
434        default:
435            PrintError("Unhandled ATAPI command %x\n", cmd);
436            atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
437            ide_raise_irq(dev, channel);
438            return -1;
439    }
440    
441    return 0;
442 }
443
444
445 static void atapi_identify_device(struct ide_drive * drive) {
446     struct ide_drive_id * drive_id = (struct ide_drive_id *)(drive->data_buf);
447     const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0";
448     const char* firmware = "ALPHA1  ";
449
450     drive->transfer_length = 512;
451     drive->transfer_index = 0;
452
453
454     memset(drive_id->buf, 0, sizeof(drive_id->buf));
455
456     drive_id->fixed_drive = 1;
457     drive_id->removable_media = 1;
458
459     // Black magic...
460     drive_id->disk_speed1 = 1;
461     drive_id->disk_speed3 = 1;
462
463     drive_id->cdrom_flag = 1;
464
465     // These buffers do not contain a terminating "\0"
466     memcpy(drive_id->serial_num, serial_number, strlen(serial_number));
467     memcpy(drive_id->firmware_rev, firmware, strlen(firmware));
468     memcpy(drive_id->model_num, drive->model, 40);
469
470     // 32 bits access
471     drive_id->dword_io = 1;
472
473     // enable LBA access
474     drive_id->lba_enable = 1;
475     
476
477     // words 64-70, 54-58 valid
478     drive_id->buf[53] = 0x0003;
479
480     // copied from CFA540A
481     drive_id->buf[63] = 0x0103; // variable (DMA stuff)
482     drive_id->buf[64] = 0x0001; // PIO
483     drive_id->buf[65] = 0x00b4;
484     drive_id->buf[66] = 0x00b4;
485     drive_id->buf[67] = 0x012c;
486     drive_id->buf[68] = 0x00b4;
487
488     drive_id->buf[71] = 30; // faked
489     drive_id->buf[72] = 30; // faked
490
491     drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4
492 }