/* getd.c */
#include
#include
#include
#include
#include
#include
#include "send_scsi_cmd.h"
#define SENSE_BYTES 18 // La dimensione del buffer di sense.
#define INQUIRY_BYTES 36 // La dimensione del buffer dati per l'Inquiry.
#define DATA_BYTES 4 // La dimensione del buffer dati alla 1a lettura.
/* Macro per la gestione del CDB della lettura dei difetti */
#define DLIST_SET_PRIMARY(cmd) cmd[2]|= 0x10
#define DLIST_SET_GROWN(cmd) cmd[2]|= 0x08
#define DLIST_SET_FORMAT_BLOCKS(cmd) cmd[2]=cmd[2]&0xf8
#define DLIST_SET_FORMAT_BFI(cmd) cmd[2]=(cmd[2]&0xf8) | 4
#define DLIST_SET_FORMAT_PHYSICAL(cmd) cmd[2]=(cmd[2]&0xf8) | 5
void print_defects(FILE * const out, char * buffer, const UWORD totdefects,
const UBYTE type_of_list)
{
ULONG cylinder, bfi, sector, * blockpnt;
UWORD cnt;
UBYTE * bpnt = buffer;
UBYTE head;
switch(type_of_list)
{
case 0: // Block format: semplici valori a 32 bit, contigui
for(cnt=0, blockpnt=(ULONG *)bpnt; cnt < totdefects; cnt++)
{
printf("Difetto n.%4u: blocco %5lu\n", cnt, blockpnt[cnt]);
}
break;
case 4: // Bytes from index format
for(cnt=0; cnt < totdefects; cnt++)
{
cylinder=*bpnt++; cylinder<<=8; cylinder|=*bpnt++;
cylinder<<=8; cylinder|=*bpnt++;
head=*bpnt++;
bfi=*bpnt++; bfi<<=8; bfi|=*bpnt++; bfi<<=8;
bfi|=*bpnt++; bfi<<=8; bfi|=*bpnt++;
printf("Difetto n.%4u: cilindro %5lu, testina %2u, B.F.I. %5lu\n", cnt,
cylinder, head, bfi);
}
break;
case 5: // Phisycal format
for(cnt=0; cnt < totdefects; cnt++)
{
cylinder=*bpnt++; cylinder<<=8; cylinder|=*bpnt++;
cylinder<<=8; cylinder|=*bpnt++;
head=*bpnt++;
sector=*bpnt++; sector<<=8; sector|=*bpnt++; sector<<=8;
sector|=*bpnt++; sector<<=8; sector|=*bpnt++;
printf("Difetto n.%4u: cilindro %5lu, testina %2u, settore %5lu\n", cnt,
cylinder, head, sector);
}
break;
default:
fprintf(out, "Formato della lista dei difetti sconosciuto!\n");
}
}
int main(int argc, char *argv[])
{
// Sintassi: nome del device, numero dell'unità.
ULONG unit;
if(argc > 2)
{
if(sscanf(argv[2], "%lu", &unit))
{
WORD retval;
UWORD totdefects, totlen;
UBYTE command[6] = { SCSI_INQUIRY, 0, 0, 0, INQUIRY_BYTES, 0};
UBYTE Scom[10] = { SCSI_DA_READ_DEFECT_DATA, 0, 0, 0, 0, 0, 0, 0, DATA_BYTES, 0};
UBYTE sensereturn[SENSE_BYTES];
struct sizedbuffer cmd, data, sense;
UBYTE * bpnt, type_of_list;
cmd.buf = command;
cmd.len = 6; // CDB a 6 bytes.
data.buf = malloc(INQUIRY_BYTES);
if(data.buf == 0)
{
printf("Out of ammo!!\n");
return 20;
}
data.len = INQUIRY_BYTES;
sense.buf = sensereturn;
sense.len = SENSE_BYTES;
retval = Send_SCSI_CMD( argv[1],
unit,
0L,
&cmd,
&data,
&sense,
0,
SCSIF_AUTOSENSE|SCSIF_READ // Fase dati in lettura.
);
if(retval == 0)
printf("Inquiry ok.\n");
else {
if((retval >> 8) == HFERR_BadStatus) // CHECK_CONDITION
printf("Errore SCSI. Status %x, vedi buffer di SENSE.\n", (UBYTE)retval);
else if(retval >> 8)
printf("Errore all'apertura dell'unità: %u\n", (retval >> 8));
return 20;
}
bpnt = data.buf;
if(bpnt[0] & 0x1fL)
{
printf("Il dispositivo scelto non è un hard-disk\n");
return 20;
}
free(data.buf);
data.buf = malloc(DATA_BYTES);
data.len = DATA_BYTES;
/* Nota: si sarebbe potuto dichiarare una variabile a 32 bit,
e poi usarla direttamente come buffer, per poter leggere così
più facilemente il valore cercato. Ma questo darebbe problemi
di portabilità tra little-endian e BIG-endian. */
DLIST_SET_PRIMARY(Scom);
DLIST_SET_FORMAT_BFI(Scom);
/* Selezione della primary list, in formato BFI, che è considerato
il più preciso. */
cmd.buf = Scom;
cmd.len = 10;
retval = Send_SCSI_CMD(argv[1],
unit,
0L,
&cmd,
&data,
&sense,
0,
SCSIF_AUTOSENSE|SCSIF_READ);
if(retval)
{
printf("Errore durante la prima lettura.\n");
free(data.buf);
return 20;
}
// Prima lettura ok....
bpnt = data.buf;
totlen= bpnt[2]<<8 | bpnt[3];
type_of_list = bpnt[1] & 7;
if(type_of_list == 0)
totdefects = totlen>>2;
else totdefects = totlen>>3;
/* La lista di tipo 0 ha descrittori da 4 bytes, le altre da 8.
Comunque il disco non dovrebbe mai ritornare un tipo di lista
diverso da quello richiesto. */
printf("Totale primary defects: %u; lista di tipo %u\n", totdefects, type_of_list);
// Riallocazione
totlen += 4; // Nella nuova dimensione si deve tenere conto dell'header.
free(data.buf);
data.buf = malloc(totlen);
if(data.buf == 0)
{
printf("Out of ammo!\n");
return 20;
}
data.len = totlen;
Scom[7] = (UBYTE)(totlen>>8);
Scom[8] = (UBYTE)totlen;
// Aggiustamento del CDB
retval = Send_SCSI_CMD(argv[1],
unit,
0L,
&cmd,
&data,
&sense,
0,
SCSIF_AUTOSENSE|SCSIF_READ);
if(retval)
{
printf("Errore durante la seconda lettura.\n");
free(data.buf);
return 20;
}
bpnt = data.buf;
print_defects(stdout, &bpnt[4], totdefects, type_of_list);
return 0;
}
}
return 0;
}