OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Apr 19, 2024 3:03 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 37 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: atapi cdrom read problem
PostPosted: Thu Jun 09, 2016 5:08 am 
Offline
Member
Member

Joined: Thu Jun 09, 2016 4:39 am
Posts: 68
I am writing code in atapi. I used codes in osdev for atapi topic(just under that),i pass through the first interrupt for outting atapi commands and in my interrupt handler i received the size of
all the bytes.but why i can't interrupt once again in reading data?(i had added some programs for sending the EOI.)below is my code.I use the bochs vm.

Code:
/*cdrom.c*/
/*cdrom.c*/

/* The default and seemingly universal sector size for CD-ROMs. */
#define ATAPI_SECTOR_SIZE 2048

/* The default ISA IRQ numbers of the ATA controllers. */
#define ATA_IRQ_PRIMARY     0x0E
#define ATA_IRQ_SECONDARY   0x0F

/* The necessary I/O ports, indexed by "bus". */
#define ATA_DATA(x)         (x)
#define ATA_FEATURES(x)     (x+1)
#define ATA_SECTOR_COUNT(x) (x+2)
#define ATA_ADDRESS1(x)     (x+3)
#define ATA_ADDRESS2(x)     (x+4)
#define ATA_ADDRESS3(x)     (x+5)
#define ATA_DRIVE_SELECT(x) (x+6)
#define ATA_COMMAND(x)      (x+7)
#define ATA_DCR(x)          (x+0x206)   /* device control register */
/* valid values for "bus" */
#define ATA_BUS_PRIMARY     0x1F0
#define ATA_BUS_SECONDARY   0x170
/* valid values for "drive" */
#define ATA_DRIVE_MASTER    0xA0
#define ATA_DRIVE_SLAVE     0xB0
char *cds;
int cd_read_flag;
int cd_irq_2;
int size;
DWORD bus = ATA_BUS_PRIMARY;
DWORD drive = ATA_DRIVE_SLAVE;
WORD cdbuffer[1024];
//cdrom irq handler
void inthandler2e(int *esp){//this is my interrupt handler it is link with idt and assembly codes
   struct BOOTINFO *binfo = (struct BOOTINFO *)ADR_BOOTINFO;
   int i;
[b]   io_out8(PIC1_OCW2, 0x66); /* IRQ-14 call is done tell the PIC1 PIC1_OCW2=a0h*/
   io_out8(PIC0_OCW2, 0x62); /* IRQ-02 call is done tell the PIC0 PIC0_OCW2=20h*/[/b]
   if(cd_irq_2==1){
      putfonts8_asc(binfo->vram, binfo->scrnx, 0, 96, COL8_FFFFFF, "get irq ata cd 2");//printing codes
   }else{
      size =(((int) io_in8(ATA_ADDRESS3 (bus))) << 8) |(int) (io_in8(ATA_ADDRESS2 (bus)));
      if(size!=ATAPI_SECTOR_SIZE){
      return;
      }
      cdbuffer[0]=0x11;
      cd_irq_2=1;
      io_in16(ATA_DATA (bus));// i have read bochs code ,firstly reading is reading all the bytes into a buffer pointer
      for(i=0;i<(size/2);i++){
         cdbuffer[i]=io_in16(ATA_DATA (bus));
      }
   }
   
   return;
}
void init_cdrom(char *vram,short scrnx){
   DWORD lba = 0x10;//in the 10h for iso there is some nozero data.
   /* 0xA8 is READ SECTORS command byte. */
   BYTE read_cmd[12] = { 0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
   BYTE status;
   int i;
   /* Tell the scheduler that this process is using the ATA subsystem. */
   //ata_grab ();
   /* Select drive (only the slave-bit is set) */
   io_out8 ( ATA_DRIVE_SELECT (bus),drive&(1<<4));
   io_nop();
   io_out8 (ATA_FEATURES (bus), 0x0);       /* PIO mode */
   //io_out8(ATA_SECTOR_COUNT(bus),0x01);
   io_out8 (ATA_ADDRESS2 (bus), (BYTE)(ATAPI_SECTOR_SIZE & 0xFF));
   io_out8 (ATA_ADDRESS3 (bus), (BYTE)(ATAPI_SECTOR_SIZE >> 8));
   io_out8 (ATA_COMMAND (bus), 0xA0);       /* ATA PACKET command */
   status = io_in8 (ATA_COMMAND (bus));
   while(status==0x80);
   io_nop();
   status = io_in8 (ATA_COMMAND (bus));
   while(!(status&0x8)&&!(status&0x01));
   sprintf(cds,"STATUS:%d",status);
   putfonts8_asc(vram, scrnx, 0, 64, COL8_FFFFFF, cds);
   read_cmd[9] = 1;              /* 1 sector */
   read_cmd[2] = (lba >> 0x18) & 0xFF;   /* most sig. byte of LBA */
   read_cmd[3] = (lba >> 0x10) & 0xFF;
   read_cmd[4] = (lba >> 0x08) & 0xFF;
   read_cmd[5] = (lba >> 0x00) & 0xFF;   /* least sig. byte of LBA */
   /* Send ATAPI/SCSI command */
   //outsw (ATA_DATA (bus), (WORD *) read_cmd, 6);
   for(i=0;i<12;i=+2){
      io_out16(ATA_DATA (bus),(read_cmd[i])|read_cmd[i+1]<<8);
   }
}

this is my interrupt codes
Code:
#define PIC0_ICW1      0x0020
#define PIC0_OCW2      0x0020
#define PIC0_IMR      0x0021
#define PIC0_ICW2      0x0021
#define PIC0_ICW3      0x0021
#define PIC0_ICW4      0x0021
#define PIC1_ICW1      0x00a0
#define PIC1_OCW2      0x00a0
#define PIC1_IMR              0x00a1
#define PIC1_ICW2      0x00a1
#define PIC1_ICW3      0x00a1
#define PIC1_ICW4      0x00a1
void init_pic(void)
/* PIC init*/
{
   io_out8(PIC0_IMR,  0xff  );
   io_out8(PIC1_IMR,  0xff  );

   io_out8(PIC0_ICW1, 0x11  );
   io_out8(PIC0_ICW2, 0x20  );
   io_out8(PIC0_ICW3, 1 << 2);
   io_out8(PIC0_ICW4, 0x01  );

   io_out8(PIC1_ICW1, 0x11  );
   io_out8(PIC1_ICW2, 0x28  );
   io_out8(PIC1_ICW3, 2     );
   io_out8(PIC1_ICW4, 0x01  );

   io_out8(PIC0_IMR,  0xfb  );
   io_out8(PIC1_IMR,  0xff  );

   return;
}

And in main code
Code:
io_out8(PIC0_IMR, 0xf9); /* PIC1 and keyboard allowed(11111001) */
io_out8(PIC1_IMR, 0xaf); /* mouse and ata0 allowed in pic1(10101111) */

In the idt code
Code:
set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);//add in code for idt

and this is my first question,i hope some guy qualify can point some errors.Thanks. :D


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Thu Jun 09, 2016 5:21 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 27, 2004 11:00 pm
Posts: 874
Location: WA
I fixed your post this time, but in the future please use code tags. It makes your post much easier to read.

_________________
## ---- ----- ------ Intel Manuals
OSdev wiki


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Thu Jun 09, 2016 1:38 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
Code:
/* Select drive (only the slave-bit is set) */
   io_out8 ( ATA_DRIVE_SELECT (bus),drive&(1<<4));

Do you set the LBA bit? How about the obsolete bits?

Code:
   status = io_in8 (ATA_COMMAND (bus));
   while(status==0x80);
   io_nop();
   status = io_in8 (ATA_COMMAND (bus));
   while(!(status&0x8)&&!(status&0x01));

uuhhmmm, 'status' will never change while in your while() loop....

You will need to change
Code:
   status = io_in8 (ATA_COMMAND (bus));
   while(status==0x80);

to
Code:
   while (io_in8 (ATA_COMMAND (bus)) == 0x80);

Also, you need to test bit 7, not see if the whole byte is 0x80.

Code:
   while (io_in8 (ATA_COMMAND (bus)) & 0x80);

You might wish to have a timeout so that you don't test for ready indefinitely.


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Thu Jun 09, 2016 2:01 pm 
Offline
Member
Member
User avatar

Joined: Sat Dec 27, 2014 9:11 am
Posts: 901
Location: Maadi, Cairo, Egypt
BenLunt wrote:
Do you set the LBA bit? How about the obsolete bits?

For ATAPI, you only need the slave bit. It says so on the Wiki and works on Bochs, VBox and QEMU.

_________________
You know your OS is advanced when you stop using the Intel programming guide as a reference.


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Thu Jun 09, 2016 4:30 pm 
Offline
Member
Member

Joined: Thu Jun 09, 2016 4:39 am
Posts: 68
I had print the status ,it is 0x88 after sending the atapi command.it's so queer because the busy bit is 1 and the drq bit is also 1
now I change the LBA mode,and chang the code for status test but status is still 0x88.
I paste the code from bochs source code 2.6.8 in iodev/harddrv.cc
In line 2328:
Code:
        case 0xa0: // SEND PACKET (atapi)
          if (BX_SELECTED_IS_CD(channel)) {
            // PACKET
            controller->packet_dma = (controller->features & 1);
            if (controller->features & (1 << 1)) {
              BX_ERROR(("PACKET-overlapped not supported"));
              command_aborted (channel, 0xa0);
            } else {
              // We're already ready!
              controller->sector_count = 1;
              controller->status.busy = 0;
              controller->status.write_fault = 0;
              // serv bit??
              controller->status.drq = 1;

              // NOTE: no interrupt here
              controller->current_command = value;
              controller->buffer_index = 0;
            }
          } else {
            command_aborted (channel, 0xa0);
          }
          break;

Is any errors for my features setting to make wrong fork?
And in line 918
Code:
case 0xa0:
          {
            unsigned index = controller->buffer_index;
            unsigned increment = 0;

            // Load block if necessary
            if (index >= controller->buffer_size) {
              if (index > controller->buffer_size)
                BX_PANIC(("index > %d : %d", controller->buffer_size, index));
              switch (BX_SELECTED_DRIVE(channel).atapi.command) {
                case 0x28: // read (10)
                case 0xa8: // read (12)
                case 0xbe: // read cd
                  if (!BX_SELECTED_DRIVE(channel).cdrom.ready) {
                    BX_PANIC(("Read with CDROM not ready"));
                  }
                  /* set status bar conditions for device */
                  bx_gui->statusbar_setitem(BX_SELECTED_DRIVE(channel).statusbar_id, 1);
                  if (!BX_SELECTED_DRIVE(channel).cdrom.cd->read_block(controller->buffer,
                                                                       BX_SELECTED_DRIVE(channel).cdrom.next_lba,
                                                                       controller->buffer_size))
                  {
                    BX_PANIC(("CDROM: read block %d failed", BX_SELECTED_DRIVE(channel).cdrom.next_lba));
                  }
                  BX_SELECTED_DRIVE(channel).cdrom.next_lba++;
                  BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks--;

                  if (!BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks) {
                    BX_SELECTED_DRIVE(channel).cdrom.curr_lba = BX_SELECTED_DRIVE(channel).cdrom.next_lba;
                    BX_DEBUG(("CDROM: last READ block loaded"));
                  } else {
                    BX_DEBUG(("CDROM: READ block loaded (%d remaining)",
                             BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks));
                  }
                  // one block transfered, start at beginning
                  index = 0;
                  break;

                default: // no need to load a new block
                  break;
              }
            }

            value32 = controller->buffer[index+increment];
            increment++;
            if (io_len >= 2) {
              value32 |= (controller->buffer[index+increment] << 8);
              increment++;
            }
            if (io_len == 4) {
              value32 |= (controller->buffer[index+increment] << 16);
              value32 |= (controller->buffer[index+increment+1] << 24);
              increment += 2;
            }
            controller->buffer_index = index + increment;
            controller->drq_index += increment;

            if (controller->drq_index >= (unsigned)BX_SELECTED_DRIVE(channel).atapi.drq_bytes) {
              controller->status.drq = 0;
              controller->drq_index = 0;

              BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining -= BX_SELECTED_DRIVE(channel).atapi.drq_bytes;

              if (BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining > 0) {
                // one or more blocks remaining (works only for single block commands)
                BX_DEBUG(("PACKET drq bytes read"));
                controller->interrupt_reason.i_o = 1;
                controller->status.busy = 0;
                controller->status.drq = 1;
                controller->interrupt_reason.c_d = 0;

                // set new byte count if last block
                if (BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining < controller->byte_count) {
                  controller->byte_count = BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining;
                }
                BX_SELECTED_DRIVE(channel).atapi.drq_bytes = controller->byte_count;

                raise_interrupt(channel);//where the interrupt goes
              } else {
                // all bytes read
                BX_DEBUG(("PACKET all bytes read"));
                controller->interrupt_reason.i_o = 1;
                controller->interrupt_reason.c_d = 1;
                controller->status.drive_ready = 1;
                controller->interrupt_reason.rel = 0;
                controller->status.busy = 0;
                controller->status.drq = 0;
                controller->status.err = 0;

                raise_interrupt(channel);//where the interrupt goes
              }
            }
            GOTO_RETURN_VALUE;
          }
          break;

It look to go in interrupt in two forks without any others.any suggestion?


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Thu Jun 09, 2016 4:53 pm 
Offline
Member
Member

Joined: Thu Jun 09, 2016 4:39 am
Posts: 68
And also for codes from osdev for "I Can't Get Interrupts Working" topic, there is "I can only receive one IRQ" problem,words as below:
Quote:
Each IRQ needs to be acknowledged to the PIC manually by sending an EOI. You need to have

Code:
outb(0x20,0x20)

Code:
outb(0x20,0x20); outb(0xa0,0x20);

Quote:
Also, if you are following the barebones tutorial, be sure that your main function doesn't exit too soon (because when it does, it disables interrupts). A common solution to make sure it doesn't exit prematurely is to add

Code:
for(;;) {
    asm("hlt");
}

And should I need add hlt code? where and how can i add this code?


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Fri Jun 10, 2016 3:00 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
How is your code coming along?

Just curious how you are coming along with this problem.

Ben


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Fri Jun 10, 2016 5:32 pm 
Offline
Member
Member

Joined: Thu Jun 09, 2016 4:39 am
Posts: 68
I copy from osdev wiki for atapi cdrom topic and copy the bochs code from the bochs source code on the net.


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Fri Jun 10, 2016 5:40 pm 
Offline
Member
Member

Joined: Thu Jun 09, 2016 4:39 am
Posts: 68
And when I use atapi to read cdrom i can not get the first irq,and I found the IMR is not zero for ata0 bit.I set it and first irq is ok,for reading data
needs anthor irq but i found when i read the data it have not interrupt but directly goes into printing code after the data reading,but all the printing is 0.


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Fri Jun 10, 2016 8:25 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
Well, here are a few pointers.

First, if you have not spun-up the disc yet, the system will need a few seconds to allow it to spin-up. Your code doesn't need to tell it to spin-up, it will do this automatically. However, you must wait for it if it hasn't yet.

Second, what is it you are trying to read? Sectors or IDENTIFY BLOCK?

If you are trying to read the IDENTIFY BLOCK, you must do it in a specific sequence. You must first send the ATA_IDENTIFY command. An ATAPI device will purposely fail, which will indicate that you can send the ATAPI_IDENTIFY command. If I remember correctly, some devices won't work until you get the IDENTIFY BLOCK using this method. After failing the ATA_IDENTIFY command, the controller will place 0x01, 0x01, 0x14, 0xEB in the parameter registers indicating an ATAPI device. You then request the ATAPI_IDENTIFY.

Next, are you assuming 16-byte packets? The packet size can be 12- or 16-bytes.

Sending the ATA_IDENTIFY command, you must wait for drive to be ready. The ATAPI_IDENTIFY command does not need to wait.

The command packet, a 12- or 16-byte packet, does not get sent via DMA. It gets sent PIO.

The IDENTIFY command, both ATA and ATAPI, must also be read using PIO. These two commands do not work if you try using DMA to read the data.

Before writing to the controller, I use the following (see the function's source below):
Code:
ata_wait(ata, ATA_STATUS_RDY, wait)

Once this returns TRUE, I write my parameters and then the command to the controller. Then I do:
Code:
ata_wait(ata, ATA_STATUS_DRQ, wait)

Once it returns TRUE, I can then read or write from/to the drive either using PIO or starting the DMA.

Here is my wait for ready code:
Code:
#define  ATA_STATUS_BSY        (1 << 7) // busy bit
#define  ATA_STATUS_RDY        (1 << 6) // Ready bit
#define  ATA_STATUS_DF         (1 << 5) // Drive Fault Error
#define  ATA_STATUS_DSC        (1 << 4) // Seek Complete   ?
#define  ATA_STATUS_DRQ        (1 << 3) // Data Ready
#define  ATA_STATUS_CORR       (1 << 2) // Data corrected  ?
#define  ATA_STATUS_IDX        (1 << 1) // Index Mark      ?
#define  ATA_STATUS_ERR        (1 << 0) // Error

// wait for the controller to return a 'not busy'
// if bit 7 is set, bits 6-0 are undefined
bool ata_wait(const struct S_ATA *ata, const bit8u ch, int timeout) {
 
  // we should always delay at least 400nS after sending a COMMAND and reading the (alt)Status register
  // therefore, read it once, ignoring the return
  inportb(ata->cntrlr->alt_base + ATA_ALT_STATUS);
 
  while (timeout) {
    bit8u status = inportb(ata->cntrlr->alt_base + ATA_ALT_STATUS);
    if (!(status & ATA_STATUS_BSY)) {
      if (status & (ATA_STATUS_ERR | ATA_STATUS_DF))
        return FALSE;
      // can be any bit of specified in ch
      if (status & ch) return TRUE;
    }
    mdelay(1);
    timeout--;
  }
}

If you will notice, if bit 7 (busy) is set, all other bits are undefined. In other words, if bit 7 is set, you must ignore all other bits.

This code is from my book (listed below). This book explains everything you need to do to detect, identify, read and write ATA and ATAPI type devices. It also (ironically) contains a cd-rom (upon proof of purchase and request) with detailed source code to read and write these devices.

On a different note, it also contains details about Floppy Disk Controllers and how to read and write from them.

I hope this helps. Let me know if you are still stuck.
Ben

http://www.fysnet.net/media_storage_devices.htm


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Sat Jun 11, 2016 1:52 am 
Offline
Member
Member

Joined: Thu Jun 09, 2016 4:39 am
Posts: 68
thank you ,ben.
I am still stuck,and my problem is in reading sectors,specially on below code:

Code:
io_in16(ATA_DATA (bus));// i have read bochs code ,firstly reading is reading all the bytes into a buffer pointer
      for(i=0;i<(size/2);i++){
         cdbuffer[i]=io_in16(ATA_DATA (bus));//size=2048bytes
      }


This code should interrupt in the second time but it have not.I add some code below:
Code:
for(i=0;i<40000000;i++){
         io_nop();
      }


I delay 4 second as atapi topic of osdev say,but i still not work.


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Sat Jun 11, 2016 9:26 am 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
Have you requested and received the IDENTIFY block yet? If you have not, you really need to.

Within that block, there is a few parameters you need. One is the size of the packet to send, 12 or 16 bytes. The other is the form of the packet, or command set to use. Bits 12:8 of the first word should be 5, meaning MMC-5, or Multi-Media Command, version 5. Bits 1:0 return the size of this packet, 12 or 16.

Code:
/* Send ATAPI/SCSI command */
   //outsw (ATA_DATA (bus), (WORD *) read_cmd, 6);
   for(i=0;i<12;i=+2){
      io_out16(ATA_DATA (bus),(read_cmd[i])|read_cmd[i+1]<<8);
   }
Your code assumes a 12-byte packet and you use the SCSI command interface, granted the SCSI command you use is the same as the MMC command.

Code:
   read_cmd[9] = 1;              /* 1 sector */
   read_cmd[2] = (lba >> 0x18) & 0xFF;   /* most sig. byte of LBA */
   read_cmd[3] = (lba >> 0x10) & 0xFF;
   read_cmd[4] = (lba >> 0x08) & 0xFF;
   read_cmd[5] = (lba >> 0x00) & 0xFF;   /* least sig. byte of LBA */

You should set bit 3 in read_cmd[1], the FUA bit, or Force Unit Access. If you do not, the hardware may just use the cache, which may or may not be up to date.

Since the command does not succeed, you should then send the Request Sense command and receive error information, which might tell you why the read command is not working.

Ben


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Sat Jun 11, 2016 3:27 pm 
Offline
Member
Member

Joined: Thu Jun 09, 2016 4:39 am
Posts: 68
thanks,ben.
but really don't know how,can you give me your example for sending IDENTIFY block?and where should i add the code of sending IDENTIFY block?

read_cmd[1]=0x04,is it right?


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Sat Jun 11, 2016 3:44 pm 
Offline
Member
Member

Joined: Thu Jun 09, 2016 4:39 am
Posts: 68
forgive me,and i also need the code how to receive IDENTIFY block and judge it as you say.thanks


Top
 Profile  
 
 Post subject: Re: atapi cdrom read problem
PostPosted: Sun Jun 12, 2016 5:27 am 
Offline
Member
Member

Joined: Thu Jun 09, 2016 4:39 am
Posts: 68
And i have anther question,my status in below code is 0x88,the busy bit is 1,i have not waited for it to change to 0,maybe it is the real error of program.
Code:
while (io_in8 (ATA_COMMAND (bus)) & 0x80);
   io_nop();


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 37 posts ]  Go to page 1, 2, 3  Next

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot], SemrushBot [Bot] and 156 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group