/* 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; }