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
index 30d829f..ad03ee9 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #define ATAPI_PACKET_SIZE 12
-#define ATAPI_BLOCK_SIZE 2048
 
 #include "atapi-types.h"
 
@@ -129,10 +128,11 @@ static void atapi_cmd_nop(struct vm_device * dev, struct ide_channel * channel)
 static int atapi_read_chunk(struct vm_device * dev, struct ide_channel * channel) {
     struct ide_drive * drive = get_selected_drive(channel);
 
-    int ret = drive->cd_ops->read(drive->data_buf, drive->cd_state.current_lba, drive->private_data);
-
+    int ret = drive->ops->read(drive->data_buf, drive->current_lba * ATAPI_BLOCK_SIZE, ATAPI_BLOCK_SIZE, 
+drive->private_data);
+    
     if (ret == -1) {
-       PrintError("IDE: Error reading CD block (LBA=%x)\n", drive->cd_state.current_lba);
+       PrintError("IDE: Error reading CD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba));
        return -1;
     }
 
@@ -148,7 +148,7 @@ static int atapi_update_data_buf(struct vm_device * dev, struct ide_channel * ch
        case 0xa8: // read(12)
 
            // Update lba address to point to next block
-           drive->cd_state.current_lba++;
+           drive->current_lba++;
 
            // read the next block
            return atapi_read_chunk(dev, channel);
@@ -166,35 +166,51 @@ static int atapi_read10(struct vm_device * dev, struct ide_channel * channel) {
     struct atapi_read10_cmd * cmd = (struct atapi_read10_cmd *)(drive->data_buf);
     uint32_t lba =  be_to_le_32(cmd->lba);
     uint16_t xfer_len = be_to_le_16(cmd->xfer_len);
-    
+
+    PrintDebug("READ10: XferLen=%d\n", xfer_len);
+
     /* Check if cd is ready
      * if not: atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
      */
-
+    
     if (xfer_len == 0) {
        atapi_cmd_nop(dev, channel);
        return 0;
     }
     
-    if ((lba + xfer_len) > drive->cd_ops->get_capacity(drive->private_data)) {
+    if (lba + xfer_len > drive->ops->get_capacity(drive->private_data)) {
+       PrintError("IDE: xfer len exceeded capacity (lba=%d) (xfer_len=%d) (ReadEnd=%d) (capacity=%d)\n", 
+                  lba, xfer_len, lba + xfer_len, 
+                  (uint32_t)drive->ops->get_capacity(drive->private_data));
        atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_LOG_BLK_OOR);
        ide_raise_irq(dev, channel);
-       return 0;}
-
+       return 0;
+    }
+       
     //    PrintDebug("Reading %d blocks from LBA 0x%x\n", xfer_len, lba);
+    
+    drive->current_lba = lba;
+       
+    // Update the request length value in the cylinder registers
+    drive->transfer_length = xfer_len * ATAPI_BLOCK_SIZE;
+    drive->transfer_index = 0; 
 
-    drive->cd_state.current_lba = lba;
+    if (channel->features.dma) {
 
-    // Update the request length value in the cylinder registers
+       if (channel->dma_status.active == 1) {
+           if (dma_read(dev, channel) == -1) {
+               PrintError("Error in DMA read for CD Read10 command\n");
+               return -1;
+           }
+       }
+       return 0;
+    }
 
     if (atapi_read_chunk(dev, channel) == -1) {
        PrintError("IDE: Could not read initial chunk from CD\n");
-       return -1;
+       return -1;
     }
-    
-    drive->transfer_length = xfer_len * ATAPI_BLOCK_SIZE;
-    drive->transfer_index = 0;
-
+       
     // Length of ATAPI buffer sits in cylinder registers
     // This is weird... The host sets this value to say what it would like to transfer, 
     // if it is larger than the correct size, the device shrinks it to the correct size
@@ -202,7 +218,7 @@ static int atapi_read10(struct vm_device * dev, struct ide_channel * channel) {
        PrintError("Could not update initial request length\n");
        return -1;
     }
-
+    
     ide_raise_irq(dev, channel);
 
     return 0;
@@ -223,7 +239,7 @@ static void atapi_req_sense(struct vm_device * dev, struct ide_channel * channel
 static int atapi_get_capacity(struct vm_device * dev, struct ide_channel * channel) {
     struct ide_drive * drive = get_selected_drive(channel);
     struct atapi_rd_capacity_resp * resp = (struct atapi_rd_capacity_resp *)(drive->data_buf);
-    uint32_t capacity = drive->cd_ops->get_capacity(drive->private_data);
+    uint32_t capacity = drive->ops->get_capacity(drive->private_data);
 
     resp->lba = le_to_be_32(capacity);
     resp->block_len = le_to_be_32(ATAPI_BLOCK_SIZE);
@@ -233,19 +249,57 @@ static int atapi_get_capacity(struct vm_device * dev, struct ide_channel * chann
     return 0;
 }
 
+static int atapi_get_config(struct vm_device * dev, struct ide_channel * channel) {
+    struct ide_drive * drive = get_selected_drive(channel);
+    struct atapi_config_cmd * cmd = (struct atapi_config_cmd *)(drive->data_buf);
+    uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
+    struct atapi_config_resp * resp = (struct atapi_config_resp *)(drive->data_buf);
+    int xfer_len = 8;
+
+    memset(resp, 0, sizeof(struct atapi_config_resp));
+
+    resp->data_len = le_to_be_32(xfer_len - 4);
+
+    if (alloc_len < xfer_len) {
+       xfer_len = alloc_len;
+    }
+    
+    atapi_setup_cmd_resp(dev, channel, xfer_len);
+    
+    return 0;
+}
+
 
 static int atapi_read_toc(struct vm_device * dev, struct ide_channel * channel) {
     struct ide_drive * drive = get_selected_drive(channel);
     struct atapi_rd_toc_cmd * cmd = (struct atapi_rd_toc_cmd *)(drive->data_buf);
     uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
-    
-
     struct atapi_rd_toc_resp * resp = (struct atapi_rd_toc_resp *)(drive->data_buf);
 
-    resp->data_len = 10;
+    int xfer_len = 12;
 
-    return -1;
+    memset(resp, 0, sizeof(struct atapi_rd_toc_resp));
+    
+    resp->data_len = le_to_be_16(10);
+    resp->first_track_num = 1;
+    resp->last_track_num = 1;
+
+    // we don't handle multi session
+    // we'll just treat it the same as single session
+    if ((cmd->format == 0) || (cmd->format == 1)) {
+       memset(&(resp->track_descs[0]), 0, 8);
+       
+       if (alloc_len < xfer_len) {
+           xfer_len = alloc_len;
+       }
+
+       atapi_setup_cmd_resp(dev, channel, xfer_len);
+    } else {
+       PrintError("Unhandled Format (%d)\n", cmd->format);
+       return -1;
+    }
 
+    return 0;
 }
 
 
@@ -351,6 +405,51 @@ static int atapi_mode_sense(struct vm_device * dev, struct ide_channel * channel
 }
 
 
+static int atapi_inquiry(struct vm_device * dev, struct ide_channel * channel) {
+    struct ide_drive * drive = get_selected_drive(channel);
+    struct atapi_inquiry_cmd * inquiry_cmd = (struct atapi_inquiry_cmd *)(drive->data_buf);
+    uint16_t alloc_len = be_to_le_16(inquiry_cmd->alloc_len);
+    struct atapi_inquiry_resp * resp = (struct atapi_inquiry_resp *)(drive->data_buf);
+    int xfer_len = sizeof(struct atapi_inquiry_resp);
+    const char * vendor_id = "VTAB    ";
+    const char * product_id = "Turbo CD-ROM    ";
+    const char * product_rev = "1.0 ";
+
+    memset(resp, 0, sizeof(struct atapi_inquiry_resp));
+    
+    resp->dev_type = DEV_TYPE_CDROM;
+    resp->removable_media = 1;
+    resp->resp_data_fmt = 0x1;
+    resp->atapi_trans_ver = 0x2;
+    resp->additional_len = 31;
+
+    memcpy(resp->t10_vendor_id, vendor_id, strlen(vendor_id));
+    memcpy(resp->product_id, product_id, strlen(product_id));
+    memcpy(resp->product_rev, product_rev, strlen(product_rev));
+    
+    if (alloc_len < xfer_len) {
+       xfer_len = alloc_len;
+    }
+
+    atapi_setup_cmd_resp(dev, channel, xfer_len);
+
+    return 0;
+}
+
+
+static int atapi_cmd_is_data_op(uint8_t cmd) {
+    switch (cmd) {
+       case 0x28: // read (10)
+       case 0xa8: // read (12)
+       case 0x2a: // write (10)
+       case 0xaa: // write (12)
+           return 1;
+       default:
+           return 0;
+    } 
+}
+
+
 static int atapi_handle_packet(struct vm_device * dev, struct ide_channel * channel) {
    struct ide_drive * drive = get_selected_drive(channel);
    uint8_t cmd = drive->data_buf[0];
@@ -371,6 +470,10 @@ static int atapi_handle_packet(struct vm_device * dev, struct ide_channel * chan
           atapi_req_sense(dev, channel);
           break;
 
+       case 0x1e: // lock door
+          atapi_cmd_nop(dev, channel);
+          break;
+
        case 0x28: // read(10)
           if (atapi_read10(dev, channel) == -1) {
               PrintError("IDE: Error in ATAPI read (%x)\n", cmd);
@@ -401,21 +504,41 @@ static int atapi_handle_packet(struct vm_device * dev, struct ide_channel * chan
           }
           break;
 
+       case 0x46: // get configuration
+          if (atapi_get_config(dev, channel) == -1) {
+              PrintError("IDE: Error getting CDROM Configuration (%x)\n", cmd);
+              return -1;
+          }
+          break;
+
+       case 0x51: // read disk info
+          // no-op to keep the Linux CD-ROM driver happy
+          PrintDebug("Error: Read disk info no-op to keep the Linux CD-ROM driver happy\n");
+          atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
+          ide_raise_irq(dev, channel);
+          break;
+
+       case 0x12: // inquiry
+          if (atapi_inquiry(dev, channel) == -1) {
+              PrintError("IDE: Error in ATAPI inquiry (%x)\n", cmd);
+              return -1;
+          }
+          break;
+
        case 0xa8: // read(12)
 
 
        case 0x1b: // start/stop drive
        case 0xbd: // mechanism status 
-       case 0x12: // inquiry
 
        case 0xbe: // read cd
 
 
 
        case 0x2b: // seek
-       case 0x1e: // lock door
+
        case 0x42: // read sub-channel
-       case 0x51: // read disk info
+
 
           
        case 0x55: // mode select
@@ -429,7 +552,7 @@ static int atapi_handle_packet(struct vm_device * dev, struct ide_channel * chan
        case 0xba: // scan
        case 0xbb: // set cd speed
        case 0x4e: // stop play/scan
-       case 0x46: // ???
        case 0x4a: // ???
        default:
           PrintError("Unhandled ATAPI command %x\n", cmd);
@@ -470,16 +593,22 @@ static void atapi_identify_device(struct ide_drive * drive) {
     // 32 bits access
     drive_id->dword_io = 1;
 
+    // enable DMA access
+    drive_id->dma_enable = 1;
+
     // enable LBA access
     drive_id->lba_enable = 1;
     
+    drive_id->rw_multiples = 0x80ff;
 
     // words 64-70, 54-58 valid
-    drive_id->buf[53] = 0x0003;
+    drive_id->field_valid = 0x0007; // DMA + pkg cmd valid
 
     // copied from CFA540A
     drive_id->buf[63] = 0x0103; // variable (DMA stuff)
-    drive_id->buf[64] = 0x0001; // PIO
+    //drive_id->buf[63] = 0x0000; // variable (DMA stuff)
+    
+    //    drive_id->buf[64] = 0x0001; // PIO
     drive_id->buf[65] = 0x00b4;
     drive_id->buf[66] = 0x00b4;
     drive_id->buf[67] = 0x012c;
@@ -488,5 +617,8 @@ static void atapi_identify_device(struct ide_drive * drive) {
     drive_id->buf[71] = 30; // faked
     drive_id->buf[72] = 30; // faked
 
-    drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4
+    //    drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4
+    drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6
+
+    drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported;
 }