No, that disk doesn't have cable select. You can see it in Google:
http://images.google.com/images?q=ST3491A
Fortunately, when it was tested, it didn't work as Slave-only, and when an IDENTIFY DEVICE command was sent to the Slave slot, the master responded, but also fortunately
the result of the command set the ERR bit to 1, but not when sent to the Master (the right slot).
The ATA-7 says that the ERR bit must be cleared to 0, and that no errors shall be reported by a device not implementing this command (an ATAPI device).
It means that this slight condition allows the program to discard that spurious detection, even when it can read valid identification data.
===================================================
Now to another problem, due to the behavior of motherboard IDE controllers, the EXECUTE DEVICE DIAGNOSTIC becomes a little unreliable, but not mainly to the device.
However, sometimes the following may happen:
- There are some ATAPI devices that respond to that command wit a value of
01 01 00 00 00 (the ATA signature!)
- There are other ATAPI devices that can report a value of
03 01 00 00 00 or
02 01 14 EB B1 or something like that.
- There are ATA devices that respond with
01 01 00 00 ?? instead of with
01 01 00 00 00
- In floating buses, due to this command, a resulting value of
FF in the Error Register may become
6F
=====================================================
Fortunately, in response to IDENTIFY DEVICE, an ATAPI device seems to at least always return the
14 EB part of the
01 01 14 EB 00 signature, and that is what we should use to know if an IDENTIFY DEVICE command was "aborted" by a device requiring IDENTIFY PACKET DEVICE.
=====================================================
Here is another awful problem that, if not handled, could eventually make fail a detection program.
The ATA-7 standard says this for command 0xEC (IDENTIFY DEVICE):
6.17.5.2 Outputs for PACKET Command feature set devices
In response to this command, devices that implement the PACKET Command feature set shall post command aborted and place the PACKET Command feature set signature in the Command Block registers (See 5.15).
And says this for command A1h (IDENTIFY PACKET DEVICE):
6.18.6 Error outputs
The device shall return command aborted if the device does not implement this command, otherwise, the device shall not report an error.
Now, we see that the standard states that both commands will set to 1 the ABRT bit in the Error Register (bit 2).
It also says that, if we send the command 0xEC to an ATAPI device, it will put its signature in the registers specified in 5.15...
The first problem is that if you send the command 0xA1 to an ATA device, it will NOT put its signature in the registers specified in 5.15...
because the standard doesn't says it, so a vendor may or may not do it
The second, and
the worst problem, is the following:
- Suppose you have an ATAPI device (a CD-DVD-R-RAM-RW...).
- Suppose that you send it the command 0xEC (IDENTIFY DEVICE) in an attempt to identify a device you know is there.
- It will surely should set the ABRT bit to 1 because you sent the command that was intended for ATA and not for ATAPI (almost the same but different)
- Now suppose that you read the ABRT bit, you see that it's 1 and also see a resemblance of the ATAPI signature specified in 5.15, so you decide to try with the other command
- Now you send the "correct" command 0xA1 (ID) and it eventually sets the DRQ bit to 1 indicating that it has the 256 words of identification ready
-
Now watch this: The device sets the
ABRT bit to 1 if you send the IDENTIFY xxxxx command that doesn't corresponds to it, but some devices do NOT clear the ABRT bit to 0 when the command is actually accepted
because the standard doesn't says it
Now, what is worse. Both commands state this in their descriptions:
The IDENTIFY DEVICE/IDENTIFY PACKET DEVICE commands eneble the host to receive parameter information from a device.....
Some devices may have to read the media in order to complete this command.
But the bold statement shoud read like this:
Some devices may or may not have to read the media in order to complete this command, EVEN WHEN SUCH COMMAND IS ABORTED.
Even if you tried to use IRQ's, with a device that aborts the command but also sends data anyway, you could not directly know if the ID is valid when you got to send the "correct" command if also the ABRT stays set to 1 by then. In those cases, maybe the "direct" solution would be to actually interptret the ID results, and if it's garbabe say something like "ATAPI incompatible" as when the BIOS had detected a device and then the PC is turned off and then it's suddenly unplugged for the next POST.
======================================
============================================
=================================================
So what we are left with is with some devices that will set the ABRT bit to 1 if you send them the "wrong" command, but when you get to send them the "right" command will NOT clear it so you could check what has happened, and since the ERR bit should normally be set to 0, and some devices require you to read the 256-word identification even when it's garbage (for them to not get stalled) when the command is NOT aborted,
you have no easy way to know when a 256-ID is valid or is a requirement even when the command was aborted, for the simple fact of setting the ABRT bit on error but not clearing it on success.
======================================
============================================
=================================================
So what we could do is this:
- Try the commands in this order:
First IDENTIFY DEVICE (0xEC)
Second IDENTIFY PACKET DEVICE (0xA1)
- If the device is ATA, it will be detected right away and will never deal with the contradictions of sending it an IDENTIFY PACKET DEVICE.
- If the device is ATAPI, if we send it the 0xEC command it will give us the ATAPI signature, and that's how we'll know that we must identify it with command 0xA1.
Now:
- Before the command, write 0 to the
Sector Count,
LBA Low,
LBA Mid and
LBA High registers.
- Send the command 0xEC
- If the command is aborted (because of ATAPI) do NOT check the ABRT bit, but instead the signature in the registers mentioned above.
- ALWAYS read 512 bytes as 256 words even when the command is aborted, just don't consider the device detected if the other checks above fail
- Now send the command 0xA1 (if the command is aborted)
- If everything is OK, then keep going. The ERR bit should still be checked for cases like the one of the ST3491A.
Here is the code I've managed to write for what I have described:
Code: Select all
EXECUTE_DEVICE_DIAGNOSTIC_signatures:
times 8 db 0 ;For Master
times 8 db 0 ;For Slave
;//This routine sets the CF to 1 if there was
;//an error (nothing found) and clears it if
;//it was successful.
;//
;//The BH register will contain the command that
;//was executed so that external functions can
;//know immediately if the device was ATA or ATAPI
;//
;//If the CARRY FLAG (CF) is set to 1, the value
;//in BH is not valid for determinining a device type,
;//neither ATA nor ATAPI.
;;;
scan_for_identify_ata_atapi_command:
push eax
push ecx
pushad
;Zero-out our special-case variables:
;;;
mov ax,0x0000
mov cx,ax
;Zero-out the relevant ATA registers to leave
;no chance of malfunction by spurious values:
;;;
add dx,2
out dx,al ;Write sector count
inc dx
out dx,al ;Write LBA Low
inc dx
out dx,al ;Write LBA Mid
inc dx
out dx,al ;Write LBA High
sub dx,5
mov bh,0xEC ;IDENTIFY DEVICE command
call identify_ata_atapi_device
jnc .allok__ATAonly
call ata_atapi__readregs
mov eax,[EXECUTE_DEVICE_DIAGNOSTIC_signatures+1]
mov ecx,0xEB140000
and eax,ecx
cmp eax,ecx
jne .deviceisnotatapi
mov cl,0x32 ;flag this as "special ATAPI"
jmp .tryatapi
.deviceisnotatapi:
xor cx,cx
.tryatapi:
cmp cl,0x32
jne .nospecialatapi
mov ch,0x64 ;flag a "special ATAPI" to not discard it by error
.nospecialatapi:
;//If the CARRY FLAG in the EFLAGS register is set,
;//we will need to execute the IDENTIFY PACKET DEVICE command
;;;
mov bh,0xA1 ;IDENTIFY PACKET DEVICE command
call identify_ata_atapi_device
jnc .allok__specials_ATAPI
.errors:
;//If the CARRY FLAG (CF) was set after that, then there is
;//no valid ATA-ATAPI drive for this bus and master/slave socket:
;;;
stc ;ERROR
jmp .end
.allok__specials_ATAPI:
; cmp ch,0x64
; jne .errors
; cmp cl,0x32
; jne .errors
.wasspecialatapi__not_an_error:
.allok__ATAonly:
clc ;All OK
.end:
call ata_atapi_showregs
popad
pop ecx
pop eax
ret
;//BH==ECh for IDENTIFY DEVICE command
;// A1h for IDENTIFY PACKET DEVICE command
;//EDX,ES:EDI must be properly set by some other functions
;;;
identify_ata_atapi_device:
push eax
push ecx
push esi
push edi
mov esi,[EXECUTE_DEVICE_DIAGNOSTIC_signatures_ptr] ;get value in the pointer
;//Send the requested command:
;;;
add dx,7
mov al,bh ;Take the command that was put in BH
out dx,al
sub dx,7
mov ecx,0xFFFF ;It still might timeout some time but has been "calibrated"
.waitdrq: ;for the slowest device in the fastest machine I have at hand
call ata_atapi__readregs
mov al,[esi+7]
test al,00001000b ;wait for DRQ==1
jnz .waitdrq_end
loop .waitdrq
.waitdrq_end:
;Write the DEVICE REGISTER
;;;
push ax
add dx,6
in al,dx ;Read DEVICE REGISTER
or al,10000001b ;Preserve all bits including DEV bit
;and...
;Set BSY and ERR/CHK
;This is for some weird buses
out dx,al ;that are half-floating and that also
;change all of their floating registers to
sub dx,6 ;the same last value written (to the device register).
pop ax ;If that's the case, it will cause the bits 0 and 7
;to be set to 1, even for the Status Register, which
;correspond to the ERR/CHK and the BSY bits,
;respectively.
;
;At the same time, those bits correspond to bits that
;are not used for the IDENTIFY DEVICE or
;IDENTIFY PACKET DEVICE commands, and correspond to
;the obsolete, ATA-3 HS0 (bit 0) and a 1 (bit 7).
call ata_atapi__readregs ;Inform the program on the device state
; ; mov al,[esi]
; ; test al,00000100b ;ABRT
; ; jnz .nocount
mov al,[esi+7]
test al,00000001b ;ERR/CHK==1 is error
jnz .nocount
test al,00001000b ;DRQ==0 is error
jz .nocount
test al,10000000b ;BSY==1 is error
jnz .nocount
clc ;All OK, the device will be counted later on
jmp .end
.nocount:
stc ;Error, the possible device will be discarded
.end:
pushf
mov esi,ata_atapi_ident_buff ;A 512-byte buffer
mov edi,esi ;Put also in EDI
call ata_atapi__r512 ;ALWAYS read the identification
call ata_atapi__pr512 ;Put it on screen
call ata_atapi__readregs ;Check the state of the registers.
popf ;This will also provide us with a delay
;equivalent to the read of 8 registers and
;at the same time will give us the complete
;register state for the selected device
pop edi
pop esi
pop ecx
pop eax
ret
ata_atapi__readregs:
pushf
push ecx
push edi
mov ecx,7
mov edi,[EXECUTE_DEVICE_DIAGNOSTIC_signatures_ptr] ;get value in the pointer
push dx
.loop
inc dx
a32 insb
loop .loop
pop dx
ror edx,16
a32 insb
ror edx,16
pop edi
pop ecx
popf
ret
====================================================
====================================================
====================================================
It has worked for me so far, but I need to know about suggestions or other alternatives. It is better to be able to disregard all these complications.