1 #include <stdarg.h> 2 #include <windef.h> 3 #include <winbase.h> 4 #include <winreg.h> 5 #include <winioctl.h> 6 #include <stdlib.h> 7 //#include <ntdddisk.h> 8 //#include <ntddscsi.h> 9 #include <ntddscsi.h> 10 #include <atapi.h> 11 #include <bm_devs.h> 12 #include <uata_ctl.h> 13 #include <tools.h> 14 #include <uniata_ver.h> 15 16 #include "helper.h" 17 18 #define DEFAULT_REMOVAL_LOCK_TIMEOUT 20 19 20 #define MOV_DW_SWP(a,b) \ 21 do \ 22 { \ 23 *(unsigned short *)&(a) = _byteswap_ushort(*(unsigned short *)&(b)); \ 24 } \ 25 while (0) 26 27 #define MOV_DD_SWP(a,b) \ 28 { \ 29 PFOUR_BYTE _from_, _to_; \ 30 _from_ = ((PFOUR_BYTE)&(b)); \ 31 _to_ = ((PFOUR_BYTE)&(a)); \ 32 __asm mov ebx,_from_ \ 33 __asm mov eax,[ebx] \ 34 __asm bswap eax \ 35 __asm mov ebx,_to_ \ 36 __asm mov [ebx],eax \ 37 } 38 39 int g_extended = 0; 40 int g_adapter_info = 0; 41 char* g_bb_list = NULL; 42 int gRadix = 16; 43 PADAPTERINFO g_AdapterInfo = NULL; 44 45 BOOLEAN 46 ata_power_mode( 47 int bus_id, 48 int dev_id, 49 int power_mode 50 ); 51 52 void print_help() { 53 printf("Usage:\n" 54 " atactl -<switches> c|s<controller id>:b<bus id>:d<device id>[:l<lun>]\n" 55 "Switches:\n" 56 " l (L)ist devices on SCSI and ATA controllers bus(es)\n" 57 " Note: ATA Pri/Sec controller are usually represented\n" 58 " as Scsi0/Scsi1 under NT-family OSes\n" 59 " x show e(X)tended info\n" 60 " a show (A)dapter info\n" 61 " s (S)can for new devices on ATA/SATA bus(es) (experimental)\n" 62 " S (S)can for new devices on ATA/SATA bus(es) (experimental)\n" 63 " device, hidden with 'H' can be redetected\n" 64 " h (H)ide device on ATA/SATA bus for removal (experimental)\n" 65 " device can be redetected\n" 66 " H (H)ide device on ATA/SATA bus (experimental)\n" 67 " device can not be redetected until 'h' or 'S' is issued\n" 68 " m [MODE] set i/o (M)ode for device or revert to default\n" 69 " available MODEs are PIO, PIO0-PIO5, DMA, WDMA0-WDMA2,\n" 70 " UDMA33/44/66/100/133, UDMA0-UDMA5\n" 71 " d [XXX] lock ATA/SATA bus for device removal for XXX seconds or\n" 72 " for %d seconds if no lock timeout specified.\n" 73 " can be used with -h, -m or standalone.\n" 74 " D [XXX] disable device (turn into sleep mode) and lock ATA/SATA bus \n" 75 " for device removal for XXX seconds or\n" 76 " for %d seconds if no lock timeout specified.\n" 77 " can be used with -h, -m or standalone.\n" 78 " pX change power state to X, where X is\n" 79 " 0 - active, 1 - idle, 2 - standby, 3 - sleep\n" 80 " r (R)eset device\n" 81 " ba (A)ssign (B)ad-block list\n" 82 " bl get assigned (B)ad-block (L)ist\n" 83 " br (R)eset assigned (B)ad-block list\n" 84 " f specify (F)ile for bad-block list\n" 85 " n XXX block (n)ubmering radix. XXX can be hex or dec\n" 86 "------\n" 87 "Examples:\n" 88 " atactl -l\n" 89 " will list all scsi buses and all connected devices\n" 90 " atactl -m udma0 s2:b1:d1\n" 91 " will switch device at Scsi2, bus 1, taget_id 1 to UDMA0 mode\n" 92 " atactl -h -d 30 c1:b0:d0:l0 \n" 93 " will hide Master (d0:l0) device on secondary (c1:b0) IDE channel\n" 94 " and lock i/o on this channel for 30 seconds to ensure safety\n" 95 " of removal process" 96 "------\n" 97 "Device address format:\n" 98 "\n" 99 "s<controller id> number of controller in system. Is assigned during hardware\n" 100 " detection. Usually s0/s1 are ATA Pri/Sec.\n" 101 " Note, due do NT internal design ATA controllers are represented\n" 102 " as SCSI controllers.\n" 103 "b<bus id> For ATA controllers it is channel number.\n" 104 " Note, usually onboard controller is represented as 2 legacy\n" 105 " ISA-compatible single-channel controllers (Scsi9/Scsi1). Additional\n" 106 " ATA, ATA-RAID and some specific onboard controllers are represented\n" 107 " as multichannel controllers.\n" 108 "d<device id> For ATA controllers d0 is Master, d1 is Slave.\n" 109 "l<lun> Not used in ATA controller drivers, alway 0\n" 110 "------\n" 111 "Bad-block list format:\n" 112 "\n" 113 "# Comment\n" 114 "; Still one comment\n" 115 "hex: switch to hexadecimal mode\n" 116 "<Bad Area 1 Start LBA, e.g. FD50> <Block count 1, e.g. 60>\n" 117 "<Bad Area 2 Start LBA> <Block count 2>\n" 118 "...\n" 119 "dec: switch to decimal mode\n" 120 "<Bad Area N Start LBA, e.g. 16384> <Block count N, e.g. 48>\n" 121 "...\n" 122 "------\n" 123 "", 124 DEFAULT_REMOVAL_LOCK_TIMEOUT, 125 DEFAULT_REMOVAL_LOCK_TIMEOUT 126 ); 127 exit(0); 128 } 129 130 #define CMD_ATA_LIST 0x01 131 #define CMD_ATA_FIND 0x02 132 #define CMD_ATA_HIDE 0x03 133 #define CMD_ATA_MODE 0x04 134 #define CMD_ATA_RESET 0x05 135 #define CMD_ATA_BBLK 0x06 136 #define CMD_ATA_POWER 0x07 137 138 HANDLE 139 ata_open_dev( 140 char* Name 141 ) 142 { 143 ULONG i; 144 HANDLE h; 145 146 for(i=0; i<4; i++) { 147 h = CreateFile(Name, 148 READ_CONTROL | GENERIC_READ | GENERIC_WRITE , 149 ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE), 150 NULL, 151 OPEN_EXISTING, 152 FILE_ATTRIBUTE_NORMAL, 153 NULL); 154 if(h && (h != ((HANDLE)(-1))) ) { 155 return h; 156 } 157 } 158 159 for(i=0; i<4; i++) { 160 h = CreateFile(Name, 161 GENERIC_READ | GENERIC_WRITE , 162 ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE), 163 NULL, 164 OPEN_EXISTING, 165 FILE_ATTRIBUTE_NORMAL, 166 NULL); 167 if(h && (h != ((HANDLE)(-1))) ) { 168 return h; 169 } 170 } 171 172 for(i=0; i<4; i++) { 173 h = CreateFile(Name, 174 GENERIC_READ, 175 ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE), 176 NULL, 177 OPEN_EXISTING, 178 FILE_ATTRIBUTE_NORMAL, 179 NULL); 180 if(h && (h != ((HANDLE)(-1))) ) { 181 return h; 182 } 183 } 184 185 for(i=0; i<4; i++) { 186 h = CreateFile(Name, 187 READ_CONTROL, 188 ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE), 189 NULL, 190 OPEN_EXISTING, 191 FILE_ATTRIBUTE_NORMAL, 192 NULL); 193 if(h && (h != ((HANDLE)(-1))) ) { 194 return h; 195 } 196 } 197 198 return NULL; 199 } // end ata_open_dev() 200 201 HANDLE 202 ata_open_file( 203 char* Name, 204 BOOLEAN create 205 ) 206 { 207 ULONG i; 208 HANDLE h; 209 210 if(!Name) { 211 if(create) { 212 return GetStdHandle(STD_OUTPUT_HANDLE); 213 } else { 214 return GetStdHandle(STD_INPUT_HANDLE); 215 } 216 } 217 218 for(i=0; i<4; i++) { 219 h = CreateFile(Name, 220 create ? GENERIC_WRITE : GENERIC_READ , 221 ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE), 222 NULL, 223 create ? CREATE_NEW : OPEN_EXISTING, 224 FILE_ATTRIBUTE_NORMAL, 225 NULL); 226 if(h && (h != ((HANDLE)(-1))) ) { 227 return h; 228 } 229 } 230 231 return NULL; 232 } // end ata_open_file() 233 234 void 235 ata_close_dev( 236 HANDLE h 237 ) 238 { 239 CloseHandle(h); 240 } // end ata_close_dev() 241 242 int 243 ata_send_ioctl( 244 HANDLE h, 245 PSCSI_ADDRESS addr, 246 PCCH Signature, 247 ULONG Ioctl, 248 PVOID inBuffer, 249 ULONG inBufferLength, 250 PVOID outBuffer, 251 ULONG outBufferLength, 252 PULONG returned 253 ) 254 { 255 ULONG status; 256 PUNIATA_CTL AtaCtl; 257 ULONG data_len = max(inBufferLength, outBufferLength); 258 ULONG len; 259 260 if(addr) { 261 len = data_len + offsetof(UNIATA_CTL, RawData); 262 } else { 263 len = data_len + sizeof(AtaCtl->hdr); 264 } 265 AtaCtl = (PUNIATA_CTL)GlobalAlloc(GMEM_FIXED, len); 266 AtaCtl->hdr.HeaderLength = sizeof(SRB_IO_CONTROL); 267 if(addr) { 268 AtaCtl->hdr.Length = data_len + offsetof(UNIATA_CTL, RawData) - sizeof(AtaCtl->hdr); 269 } else { 270 AtaCtl->hdr.Length = data_len; 271 } 272 273 memcpy(&AtaCtl->hdr.Signature, Signature, 8); 274 275 AtaCtl->hdr.Timeout = 10000; 276 AtaCtl->hdr.ControlCode = Ioctl; 277 AtaCtl->hdr.ReturnCode = 0; 278 279 if(addr) { 280 AtaCtl->addr = *addr; 281 AtaCtl->addr.Length = sizeof(AtaCtl->addr); 282 } 283 284 if(outBufferLength) { 285 if(addr) { 286 memset(&AtaCtl->RawData, 0, outBufferLength); 287 } else { 288 memset(&AtaCtl->addr, 0, outBufferLength); 289 } 290 } 291 292 if(inBuffer && inBufferLength) { 293 if(addr) { 294 memcpy(&AtaCtl->RawData, inBuffer, inBufferLength); 295 } else { 296 memcpy(&AtaCtl->addr, inBuffer, inBufferLength); 297 } 298 } 299 300 status = DeviceIoControl(h, 301 IOCTL_SCSI_MINIPORT, 302 AtaCtl, 303 len, 304 AtaCtl, 305 len, 306 returned, 307 FALSE); 308 309 if(outBuffer && outBufferLength) { 310 if(addr) { 311 memcpy(outBuffer, &AtaCtl->RawData, outBufferLength); 312 } else { 313 memcpy(outBuffer, &AtaCtl->addr, outBufferLength); 314 } 315 } 316 GlobalFree(AtaCtl); 317 318 if(!status) { 319 status = GetLastError(); 320 return FALSE; 321 } 322 return TRUE; 323 } // end ata_send_ioctl() 324 325 int 326 ata_send_scsi( 327 HANDLE h, 328 PSCSI_ADDRESS addr, 329 PCDB cdb, 330 UCHAR cdbLength, 331 PVOID Buffer, 332 ULONG BufferLength, 333 BOOLEAN DataIn, 334 PSENSE_DATA senseData, 335 PULONG returned 336 ) 337 { 338 ULONG status; 339 PSCSI_PASS_THROUGH_WITH_BUFFERS sptwb; 340 //ULONG data_len = BufferLength; 341 ULONG len; 342 343 len = BufferLength + offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf); 344 345 sptwb = (PSCSI_PASS_THROUGH_WITH_BUFFERS)GlobalAlloc(GMEM_FIXED, len); 346 if(!sptwb) { 347 return FALSE; 348 } 349 memset(sptwb, 0, offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf)); 350 351 sptwb->spt.Length = sizeof(SCSI_PASS_THROUGH); 352 sptwb->spt.PathId = addr->PathId; 353 sptwb->spt.TargetId = addr->TargetId; 354 sptwb->spt.Lun = addr->Lun; 355 sptwb->spt.CdbLength = cdbLength; 356 sptwb->spt.SenseInfoLength = 24; 357 sptwb->spt.DataIn = Buffer ? (DataIn ? SCSI_IOCTL_DATA_IN : SCSI_IOCTL_DATA_OUT) : 0; 358 sptwb->spt.DataTransferLength = BufferLength; 359 sptwb->spt.TimeOutValue = 10; 360 sptwb->spt.DataBufferOffset = 361 offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf); 362 sptwb->spt.SenseInfoOffset = 363 offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf); 364 memcpy(&sptwb->spt.Cdb, cdb, cdbLength); 365 366 if(Buffer && !DataIn) { 367 memcpy(&sptwb->ucSenseBuf, Buffer, BufferLength); 368 } 369 370 status = DeviceIoControl(h, 371 IOCTL_SCSI_PASS_THROUGH, 372 sptwb, 373 (Buffer && !DataIn) ? len : sizeof(SCSI_PASS_THROUGH), 374 sptwb, 375 (Buffer && DataIn) ? len : offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf), 376 returned, 377 FALSE); 378 379 if(Buffer && DataIn) { 380 memcpy(Buffer, &sptwb->ucDataBuf, BufferLength); 381 } 382 if(senseData) { 383 memcpy(senseData, &sptwb->ucSenseBuf, sizeof(sptwb->ucSenseBuf)); 384 } 385 386 GlobalFree(sptwb); 387 388 if(!status) { 389 status = GetLastError(); 390 return FALSE; 391 } 392 return TRUE; 393 } // end ata_send_scsi() 394 395 IO_SCSI_CAPABILITIES g_capabilities; 396 UCHAR g_inquiry_buffer[2048]; 397 398 void 399 ata_mode_to_str( 400 char* str, 401 int mode 402 ) 403 { 404 if(mode > ATA_SA600) { 405 sprintf(str, "SATA-600+"); 406 } else 407 if(mode >= ATA_SA600) { 408 sprintf(str, "SATA-600"); 409 } else 410 if(mode >= ATA_SA300) { 411 sprintf(str, "SATA-300"); 412 } else 413 if(mode >= ATA_SA150) { 414 sprintf(str, "SATA-150"); 415 } else 416 if(mode >= ATA_UDMA0) { 417 sprintf(str, "UDMA%d", mode-ATA_UDMA0); 418 } else 419 if(mode >= ATA_WDMA0) { 420 sprintf(str, "WDMA%d", mode-ATA_WDMA0); 421 } else 422 if(mode >= ATA_SDMA0) { 423 sprintf(str, "SDMA%d", mode-ATA_SDMA0); 424 } else 425 if(mode >= ATA_PIO0) { 426 sprintf(str, "PIO%d", mode-ATA_PIO0); 427 } else 428 if(mode == ATA_PIO_NRDY) { 429 sprintf(str, "PIO nRDY"); 430 } else 431 { 432 sprintf(str, "PIO"); 433 } 434 } // end ata_mode_to_str() 435 436 #define check_atamode_str(str, mode) \ 437 (!_stricmp(str, "UDMA" #mode) || \ 438 !_stricmp(str, "UDMA-" #mode) || \ 439 !_stricmp(str, "ATA-" #mode) || \ 440 !_stricmp(str, "ATA#" #mode)) 441 442 int 443 ata_str_to_mode( 444 char* str 445 ) 446 { 447 int mode; 448 size_t len; 449 450 if(!_stricmp(str, "SATA600")) 451 return ATA_SA600; 452 if(!_stricmp(str, "SATA300")) 453 return ATA_SA300; 454 if(!_stricmp(str, "SATA150")) 455 return ATA_SA150; 456 if(!_stricmp(str, "SATA")) 457 return ATA_SA150; 458 459 if(check_atamode_str(str, 16)) 460 return ATA_UDMA0; 461 if(check_atamode_str(str, 25)) 462 return ATA_UDMA1; 463 if(check_atamode_str(str, 33)) 464 return ATA_UDMA2; 465 if(check_atamode_str(str, 44)) 466 return ATA_UDMA3; 467 if(check_atamode_str(str, 66)) 468 return ATA_UDMA4; 469 if(check_atamode_str(str, 100)) 470 return ATA_UDMA5; 471 if(check_atamode_str(str, 122)) 472 return ATA_UDMA6; 473 474 len = strlen(str); 475 476 if(len >= 4 && !_memicmp(str, "UDMA", 4)) { 477 if(len == 4) 478 return ATA_UDMA0; 479 if(len > 5) 480 return -1; 481 mode = str[4] - '0'; 482 if(mode < 0 || mode > 7) 483 return -1; 484 return ATA_UDMA0+mode; 485 } 486 if(len >= 4 && !_memicmp(str, "WDMA", 4)) { 487 if(len == 4) 488 return ATA_WDMA0; 489 if(len > 5) 490 return -1; 491 mode = str[4] - '0'; 492 if(mode < 0 || mode > 2) 493 return -1; 494 return ATA_WDMA0+mode; 495 } 496 if(len >= 4 && !_memicmp(str, "SDMA", 4)) { 497 if(len == 4) 498 return ATA_SDMA0; 499 if(len > 5) 500 return -1; 501 mode = str[4] - '0'; 502 if(mode < 0 || mode > 2) 503 return -1; 504 return ATA_SDMA0+mode; 505 } 506 if(len == 4 && !_memicmp(str, "DMA", 4)) { 507 return ATA_SDMA0; 508 } 509 if(len >= 3 && !_memicmp(str, "PIO", 3)) { 510 if(len == 3) 511 return ATA_PIO; 512 if(len > 4) 513 return -1; 514 mode = str[3] - '0'; 515 if(mode < 0 || mode > 5) 516 return -1; 517 return ATA_PIO0+mode; 518 } 519 520 return -1; 521 } // end ata_str_to_mode() 522 523 ULONG 524 EncodeVendorStr( 525 OUT char* Buffer, 526 IN PUCHAR Str, 527 IN ULONG Length, 528 IN ULONG Xorer 529 ) 530 { 531 ULONG i,j; 532 UCHAR a; 533 534 for(i=0, j=0; i<Length; i++, j++) { 535 a = Str[i ^ Xorer]; 536 if(!a) { 537 Buffer[j] = 0; 538 return j; 539 } else 540 if(a == ' ') { 541 Buffer[j] = '_'; 542 } else 543 if((a == '_') || 544 (a == '#') || 545 (a == '\\') || 546 (a == '\"') || 547 (a == '\'') || 548 (a < ' ') || 549 (a >= 127)) { 550 Buffer[j] = '#'; 551 j++; 552 sprintf(Buffer+j, "%2.2x", a); 553 j++; 554 } else { 555 Buffer[j] = a; 556 } 557 } 558 Buffer[j] = 0; 559 return j; 560 } // end EncodeVendorStr() 561 562 HKEY 563 ata_get_bblist_regh( 564 IN PIDENTIFY_DATA ident, 565 OUT char* DevSerial, 566 BOOLEAN read_only 567 ) 568 { 569 HKEY hKey = NULL; 570 HKEY hKey2 = NULL; 571 ULONG Length; 572 REGSAM access = read_only ? KEY_READ : KEY_ALL_ACCESS; 573 574 Length = EncodeVendorStr(DevSerial, (PUCHAR)ident->ModelNumber, sizeof(ident->ModelNumber), 0x01); 575 DevSerial[Length] = '-'; 576 Length++; 577 Length += EncodeVendorStr(DevSerial+Length, ident->SerialNumber, sizeof(ident->SerialNumber), 0x01); 578 579 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\UniATA", NULL, access, &hKey) != ERROR_SUCCESS) { 580 hKey = NULL; 581 goto exit; 582 } 583 if(RegOpenKey(hKey, "Parameters", &hKey2) != ERROR_SUCCESS) { 584 hKey2 = NULL; 585 if(read_only || (RegCreateKey(hKey, "Parameters", &hKey2) != ERROR_SUCCESS)) { 586 hKey2 = NULL; 587 goto exit; 588 } 589 } 590 RegCloseKey(hKey2); 591 if(RegOpenKey(hKey, "Parameters\\BadBlocks", &hKey2) != ERROR_SUCCESS) { 592 hKey2 = NULL; 593 if(read_only || (RegCreateKey(hKey, "Parameters\\BadBlocks", &hKey2) != ERROR_SUCCESS)) { 594 hKey2 = NULL; 595 goto exit; 596 } 597 } 598 599 exit: 600 if(hKey) 601 RegCloseKey(hKey); 602 603 return hKey2; 604 } // end ata_get_bblist_regh() 605 606 IDENTIFY_DATA g_ident; 607 608 int 609 ata_check_unit( 610 HANDLE h, // handle to ScsiXXX: 611 int dev_id 612 ) 613 { 614 ULONG status; 615 ULONG returned; 616 617 PSCSI_ADAPTER_BUS_INFO adapterInfo; 618 PSCSI_INQUIRY_DATA inquiryData; 619 SCSI_ADDRESS addr; 620 ULONG i, j; 621 int l_dev_id; 622 ULONG len; 623 GETTRANSFERMODE IoMode; 624 PSENDCMDOUTPARAMS pout; 625 PIDENTIFY_DATA ident; 626 PINQUIRYDATA scsi_ident; 627 char buff[sizeof(SENDCMDOUTPARAMS)+/*sizeof(IDENTIFY_DATA)*/2048]; 628 char mode_str[12]; 629 //ULONG bus_id = (dev_id >> 24) & 0xff; 630 BOOLEAN found = FALSE; 631 SENDCMDINPARAMS pin; 632 int io_mode = -1; 633 char SerNum[128]; 634 char DevSerial[128]; 635 char lun_str[10]; 636 HKEY hKey2; 637 ULONGLONG max_lba = -1; 638 USHORT chs[3] = { 0 }; 639 640 if(dev_id != -1) { 641 dev_id &= 0x00ffffff; 642 } 643 if(dev_id == 0x007f7f7f) { 644 return TRUE; 645 } 646 647 pout = (PSENDCMDOUTPARAMS)buff; 648 ident = (PIDENTIFY_DATA)&(pout->bBuffer); 649 650 status = DeviceIoControl(h, 651 IOCTL_SCSI_GET_INQUIRY_DATA, 652 NULL, 653 0, 654 g_inquiry_buffer, 655 sizeof(g_inquiry_buffer), 656 &returned, 657 FALSE); 658 659 if(!status) { 660 printf("Can't get device info\n"); 661 return FALSE; 662 } 663 664 // Note: adapterInfo->NumberOfBuses is 1 greater than g_AdapterInfo->NumberChannels 665 // because of virtual communication port 666 adapterInfo = (PSCSI_ADAPTER_BUS_INFO)g_inquiry_buffer; 667 for (i = 0; i+1 < adapterInfo->NumberOfBuses; i++) { 668 inquiryData = (PSCSI_INQUIRY_DATA) (g_inquiry_buffer + 669 adapterInfo->BusData[i].InquiryDataOffset); 670 671 if(g_extended && g_AdapterInfo && g_AdapterInfo->ChanHeaderLengthValid && 672 g_AdapterInfo->NumberChannels < i) { 673 PCHANINFO ChanInfo; 674 675 ChanInfo = (PCHANINFO) 676 (((PCHAR)g_AdapterInfo)+ 677 sizeof(ADAPTERINFO)+ 678 g_AdapterInfo->ChanHeaderLength*i); 679 680 io_mode = ChanInfo->MaxTransferMode; 681 if(io_mode != -1) { 682 ata_mode_to_str(mode_str, io_mode); 683 } else { 684 mode_str[0] = 0; 685 } 686 printf(" b%lu [%s]\n", 687 i, 688 mode_str 689 ); 690 } 691 692 while (adapterInfo->BusData[i].InquiryDataOffset) { 693 /* 694 if(dev_id/adapterInfo->BusData[i].NumberOfLogicalUnits == 695 inquiryData->TargetId && 696 dev_id%adapterInfo->BusData[i].NumberOfLogicalUnits == 697 inquiryData->Lun) { 698 printf(" %d %d %3d %s %.28s ", 699 i, 700 inquiryData->TargetId, 701 inquiryData->Lun, 702 (inquiryData->DeviceClaimed) ? "Y" : "N", 703 &inquiryData->InquiryData[8]); 704 }*/ 705 l_dev_id = (i << 16) | ((ULONG)(inquiryData->TargetId) << 8) | inquiryData->Lun; 706 707 if(l_dev_id == dev_id || dev_id == -1) { 708 709 scsi_ident = (PINQUIRYDATA)&(inquiryData->InquiryData); 710 if(!memcmp(&(scsi_ident->VendorId[0]), UNIATA_COMM_PORT_VENDOR_STR, 24)) { 711 // skip communication port 712 goto next_dev; 713 } 714 715 found = TRUE; 716 717 if(inquiryData->Lun) { 718 sprintf(lun_str, ":l%d", inquiryData->Lun); 719 } else { 720 sprintf(lun_str, " "); 721 } 722 723 724 /* 725 for (j = 0; j < 8; j++) { 726 printf("%02X ", inquiryData->InquiryData[j]); 727 } 728 */ 729 730 addr.Length = sizeof(addr); 731 addr.PortNumber = -1; 732 addr.PathId = inquiryData->PathId; 733 addr.TargetId = inquiryData->TargetId; 734 addr.Lun = inquiryData->Lun; 735 status = ata_send_ioctl(h, &addr, "-UNIATA-", 736 IOCTL_SCSI_MINIPORT_UNIATA_GET_MODE, 737 NULL, 0, 738 &IoMode, sizeof(IoMode), 739 &returned); 740 if(status) { 741 //io_mode = min(IoMode.CurrentMode, IoMode.MaxMode); 742 io_mode = IoMode.PhyMode; 743 if(!io_mode) { 744 io_mode = min(max(IoMode.CurrentMode,IoMode.OrigMode),IoMode.MaxMode); 745 } 746 } else { 747 io_mode = -1; 748 } 749 750 memset(&pin, 0, sizeof(pin)); 751 memset(buff, 0, sizeof(buff)); 752 pin.irDriveRegs.bCommandReg = ID_CMD; 753 // this is valid for IDE/ATA, where only 2 devices can be attached to the bus. 754 // probably, we shall change this in future to support SATA splitters 755 pin.bDriveNumber = inquiryData->PathId*2+inquiryData->TargetId; 756 757 status = ata_send_ioctl(h, NULL, "SCSIDISK", 758 IOCTL_SCSI_MINIPORT_IDENTIFY, 759 &pin, sizeof(pin), 760 buff, sizeof(buff), 761 &returned); 762 763 if(!status) { 764 memset(&pin, 0, sizeof(pin)); 765 memset(buff, 0, sizeof(buff)); 766 pin.irDriveRegs.bCommandReg = ATAPI_ID_CMD; 767 // this is valid for IDE/ATA, where only 2 devices can be attached to the bus. 768 // probably, we shall change this in future to support SATA splitters 769 pin.bDriveNumber = inquiryData->PathId*2+inquiryData->TargetId; 770 771 status = ata_send_ioctl(h, NULL, "SCSIDISK", 772 IOCTL_SCSI_MINIPORT_IDENTIFY, 773 &pin, sizeof(pin), 774 buff, sizeof(buff), 775 &returned); 776 777 } 778 779 if(!g_extended) { 780 printf(" b%lu:d%d%s %24.24s %4.4s ", 781 i, 782 inquiryData->TargetId, 783 lun_str, 784 /*(inquiryData->DeviceClaimed) ? "Y" : "N",*/ 785 (g_extended ? (PUCHAR)"" : &scsi_ident->VendorId[0]), 786 (g_extended ? (PUCHAR)"" : &scsi_ident->ProductRevisionLevel[0]) 787 ); 788 } else { 789 printf(" b%lu:d%d%s ", 790 i, 791 inquiryData->TargetId, 792 lun_str 793 ); 794 } 795 796 if(status) { 797 if(io_mode == -1) { 798 io_mode = ata_cur_mode_from_ident(ident, IDENT_MODE_ACTIVE); 799 } 800 } 801 if(io_mode != -1) { 802 ata_mode_to_str(mode_str, io_mode); 803 } 804 if(!g_extended || !status) { 805 if(g_extended) { 806 printf(" %24.24s %4.4s ", 807 (&inquiryData->InquiryData[8]), 808 (&inquiryData->InquiryData[8+24]) 809 ); 810 } 811 if(io_mode != -1) { 812 printf(" %.12s ", mode_str); 813 } 814 } 815 printf("\n"); 816 817 if(g_extended) { 818 if(status) { 819 820 BOOLEAN BlockMode_valid = TRUE; 821 BOOLEAN print_geom = FALSE; 822 823 switch(ident->DeviceType) { 824 case ATAPI_TYPE_DIRECT: 825 if(ident->Removable) { 826 printf(" Floppy "); 827 } else { 828 printf(" Hard Drive "); 829 } 830 break; 831 case ATAPI_TYPE_TAPE: 832 printf(" Tape Drive "); 833 break; 834 case ATAPI_TYPE_CDROM: 835 printf(" CD/DVD Drive "); 836 BlockMode_valid = FALSE; 837 break; 838 case ATAPI_TYPE_OPTICAL: 839 printf(" Optical Drive "); 840 BlockMode_valid = FALSE; 841 break; 842 default: 843 printf(" Hard Drive "); 844 print_geom = TRUE; 845 //MOV_DD_SWP(max_lba, ident->UserAddressableSectors); 846 max_lba = ident->UserAddressableSectors; 847 if(ident->FeaturesSupport.Address48) { 848 max_lba = ident->UserAddressableSectors48; 849 } 850 //MOV_DW_SWP(chs[0], ident->NumberOfCylinders); 851 //MOV_DW_SWP(chs[1], ident->NumberOfHeads); 852 //MOV_DW_SWP(chs[2], ident->SectorsPerTrack); 853 chs[0] = ident->NumberOfCylinders; 854 chs[1] = ident->NumberOfHeads; 855 chs[2] = ident->SectorsPerTrack; 856 if(!max_lba) { 857 max_lba = (ULONG)(chs[0])*(ULONG)(chs[1])*(ULONG)(chs[2]); 858 } 859 } 860 if(io_mode != -1) { 861 printf(" %.12s\n", mode_str); 862 } 863 for (j = 0; j < 40; j += 2) { 864 MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->ModelNumber)[j]); 865 } 866 printf(" Mod: %40.40s\n", SerNum); 867 for (j = 0; j < 8; j += 2) { 868 MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->FirmwareRevision)[j]); 869 } 870 printf(" Rev: %8.8s\n", SerNum); 871 for (j = 0; j < 20; j += 2) { 872 MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->SerialNumber)[j]); 873 } 874 printf(" S/N: %20.20s\n", SerNum); 875 876 if(BlockMode_valid) { 877 if(ident->MaximumBlockTransfer) { 878 printf(" Multi-block mode: %u block%s\n", ident->MaximumBlockTransfer, ident->MaximumBlockTransfer == 1 ? "" : "s"); 879 } else { 880 printf(" Multi-block mode: N/A\n"); 881 } 882 } 883 if(print_geom) { 884 printf(" C/H/S: %u/%u/%u \n", chs[0], chs[1], chs[2]); 885 printf(" LBA: %I64u \n", max_lba); 886 if(max_lba < 2) { 887 printf(" Size: %lu kb\n", (ULONG)(max_lba/2)); 888 } else 889 if(max_lba < 2*1024*1024) { 890 printf(" Size: %lu Mb\n", (ULONG)(max_lba/2048)); 891 } else 892 if(max_lba < (ULONG)2*1024*1024*1024) { 893 printf(" Size: %lu.%lu (%lu) Gb\n", (ULONG)(max_lba/2048/1024), 894 (ULONG)(((max_lba/2048)%1024)/10), 895 (ULONG)(max_lba*512/1000/1000/1000) 896 ); 897 } else { 898 printf(" Size: %lu.%lu (%lu) Tb\n", (ULONG)(max_lba/2048/1024/1024), 899 (ULONG)((max_lba/2048/1024)%1024)/10, 900 (ULONG)(max_lba*512/1000/1000/1000) 901 ); 902 } 903 } 904 len = 0; 905 if((hKey2 = ata_get_bblist_regh(ident, DevSerial, TRUE))) { 906 if(RegQueryValueEx(hKey2, DevSerial, NULL, NULL, NULL, &len) == ERROR_SUCCESS) { 907 printf(" !!! Assigned bad-block list !!!\n"); 908 } 909 RegCloseKey(hKey2); 910 } 911 } else { 912 switch(scsi_ident->DeviceType) { 913 case DIRECT_ACCESS_DEVICE: 914 if(scsi_ident->RemovableMedia) { 915 printf(" Floppy "); 916 } else { 917 printf(" Hard Drive "); 918 } 919 break; 920 case SEQUENTIAL_ACCESS_DEVICE: 921 printf(" Tape Drive "); 922 break; 923 case PRINTER_DEVICE: 924 printf(" Printer "); 925 break; 926 case PROCESSOR_DEVICE: 927 printf(" Processor "); 928 break; 929 case WRITE_ONCE_READ_MULTIPLE_DEVICE: 930 printf(" WORM Drive "); 931 break; 932 case READ_ONLY_DIRECT_ACCESS_DEVICE: 933 printf(" CDROM Drive "); 934 break; 935 case SCANNER_DEVICE: 936 printf(" Scanner "); 937 break; 938 case OPTICAL_DEVICE: 939 printf(" Optical Drive "); 940 break; 941 case MEDIUM_CHANGER: 942 printf(" Changer "); 943 break; 944 case COMMUNICATION_DEVICE: 945 printf(" Comm. device "); 946 break; 947 } 948 printf("\n"); 949 } 950 } 951 memcpy(&g_ident, ident, sizeof(IDENTIFY_DATA)); 952 } 953 next_dev: 954 if (inquiryData->NextInquiryDataOffset == 0) { 955 break; 956 } 957 958 inquiryData = (PSCSI_INQUIRY_DATA) (g_inquiry_buffer + 959 inquiryData->NextInquiryDataOffset); 960 } 961 } 962 if(!found) { 963 printf(" No device(s) found.\n"); 964 return FALSE; 965 } 966 967 return TRUE; 968 } // end ata_check_unit() 969 970 BOOLEAN 971 ata_adapter_info( 972 int bus_id, 973 int print_info 974 ) 975 { 976 char dev_name[64]; 977 HANDLE h; 978 PADAPTERINFO AdapterInfo; 979 ULONG status; 980 ULONG returned; 981 SCSI_ADDRESS addr; 982 PCI_SLOT_NUMBER slotData; 983 char mode_str[12]; 984 ULONG len; 985 986 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id); 987 h = ata_open_dev(dev_name); 988 if(!h) 989 return FALSE; 990 addr.Length = sizeof(addr); 991 addr.PortNumber = bus_id; 992 993 len = sizeof(ADAPTERINFO)+sizeof(CHANINFO)*AHCI_MAX_PORT; 994 if(!g_AdapterInfo) { 995 AdapterInfo = (PADAPTERINFO)GlobalAlloc(GMEM_FIXED, len); 996 if(!AdapterInfo) { 997 ata_close_dev(h); 998 return FALSE; 999 } 1000 } else { 1001 AdapterInfo = g_AdapterInfo; 1002 } 1003 memset(AdapterInfo, 0, len); 1004 1005 status = ata_send_ioctl(h, &addr, "-UNIATA-", 1006 IOCTL_SCSI_MINIPORT_UNIATA_ADAPTER_INFO, 1007 AdapterInfo, len, 1008 AdapterInfo, len, 1009 &returned); 1010 if(status) { 1011 ata_mode_to_str(mode_str, AdapterInfo->MaxTransferMode); 1012 } 1013 printf("Scsi%d: %s %s\n", bus_id, status ? "[UniATA]" : "", status ? mode_str : ""); 1014 if(print_info) { 1015 if(!status) { 1016 printf("Can't get adapter info\n"); 1017 } else { 1018 if(AdapterInfo->AdapterInterfaceType == PCIBus) { 1019 slotData.u.AsULONG = AdapterInfo->slotNumber; 1020 printf(" PCI Bus/Dev/Func: %lu/%lu/%lu%s\n", 1021 AdapterInfo->SystemIoBusNumber, slotData.u.bits.DeviceNumber, slotData.u.bits.FunctionNumber, 1022 AdapterInfo->AdapterInterfaceType == AdapterInfo->OrigAdapterInterfaceType ? "" : " (ISA-Bridged)"); 1023 printf(" VendorId/DevId/Rev: %#04x/%#04x/%#02x\n", 1024 (USHORT)(AdapterInfo->DevID >> 16), 1025 (USHORT)(AdapterInfo->DevID & 0xffff), 1026 (UCHAR)(AdapterInfo->RevID)); 1027 if(AdapterInfo->DeviceName[0]) { 1028 printf(" Name: %s\n", AdapterInfo->DeviceName); 1029 } 1030 } else 1031 if(AdapterInfo->AdapterInterfaceType == Isa) { 1032 printf(" ISA Bus\n"); 1033 } 1034 printf(" IRQ: %ld\n", AdapterInfo->BusInterruptLevel); 1035 } 1036 } 1037 ata_close_dev(h); 1038 //GlobalFree(AdapterInfo); 1039 g_AdapterInfo = AdapterInfo; 1040 return status ? TRUE : FALSE; 1041 } // end ata_adapter_info() 1042 1043 int 1044 ata_check_controller( 1045 HANDLE h, // handle to ScsiXXX: 1046 PIO_SCSI_CAPABILITIES capabilities 1047 ) 1048 { 1049 ULONG status; 1050 ULONG returned; 1051 1052 status = DeviceIoControl(h, 1053 IOCTL_SCSI_GET_CAPABILITIES, 1054 NULL, 1055 0, 1056 capabilities, 1057 sizeof(IO_SCSI_CAPABILITIES), 1058 &returned, 1059 FALSE); 1060 return status; 1061 } // end ata_check_controller() 1062 1063 BOOLEAN 1064 ata_list( 1065 int bus_id, 1066 int dev_id 1067 ) 1068 { 1069 char dev_name[64]; 1070 HANDLE h; 1071 //BOOLEAN uniata_driven; 1072 1073 if(bus_id == -1) { 1074 for(bus_id=0; TRUE; bus_id++) { 1075 if(!ata_list(bus_id, dev_id)) 1076 break; 1077 } 1078 return TRUE; 1079 } 1080 /*uniata_driven =*/ ata_adapter_info(bus_id, g_adapter_info); 1081 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id); 1082 h = ata_open_dev(dev_name); 1083 if(!h) 1084 return FALSE; 1085 if(dev_id == -1) { 1086 ata_check_controller(h, &g_capabilities); 1087 ata_check_unit(h, -1); 1088 ata_close_dev(h); 1089 return TRUE; 1090 } 1091 ata_check_unit(h, dev_id | (bus_id << 24)); 1092 ata_close_dev(h); 1093 return TRUE; 1094 } // end ata_list() 1095 1096 BOOLEAN 1097 ata_mode( 1098 int bus_id, 1099 int dev_id, 1100 int mode 1101 ) 1102 { 1103 char dev_name[64]; 1104 HANDLE h; 1105 SETTRANSFERMODE IoMode; 1106 ULONG status; 1107 ULONG returned; 1108 SCSI_ADDRESS addr; 1109 1110 if(dev_id == -1) { 1111 return FALSE; 1112 } 1113 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id); 1114 h = ata_open_dev(dev_name); 1115 if(!h) 1116 return FALSE; 1117 addr.Length = sizeof(addr); 1118 addr.PortNumber = bus_id; 1119 addr.PathId = (UCHAR)(dev_id >> 16); 1120 addr.TargetId = (UCHAR)(dev_id >> 8); 1121 addr.Lun = (UCHAR)(dev_id); 1122 1123 IoMode.MaxMode = mode; 1124 IoMode.ApplyImmediately = FALSE; 1125 // IoMode.ApplyImmediately = TRUE; 1126 IoMode.OrigMode = mode; 1127 1128 status = ata_send_ioctl(h, &addr, "-UNIATA-", 1129 IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE, 1130 &IoMode, sizeof(IoMode), 1131 NULL, 0, 1132 &returned); 1133 if(!status) { 1134 printf("Can't apply specified transfer mode\n"); 1135 } else { 1136 ata_mode_to_str(dev_name, mode); 1137 printf("Transfer rate switched to %s\n", dev_name); 1138 } 1139 ata_close_dev(h); 1140 return status ? TRUE : FALSE; 1141 } // end ata_mode() 1142 1143 BOOLEAN 1144 ata_reset( 1145 int bus_id, 1146 int dev_id 1147 ) 1148 { 1149 char dev_name[64]; 1150 HANDLE h; 1151 ULONG status; 1152 ULONG returned; 1153 SCSI_ADDRESS addr; 1154 1155 if(dev_id == -1) { 1156 return FALSE; 1157 } 1158 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id); 1159 h = ata_open_dev(dev_name); 1160 if(!h) 1161 return FALSE; 1162 addr.Length = sizeof(addr); 1163 addr.PortNumber = bus_id; 1164 addr.PathId = (UCHAR)(dev_id >> 16); 1165 addr.TargetId = (UCHAR)(dev_id >> 8); 1166 addr.Lun = (UCHAR)(dev_id); 1167 1168 if(addr.TargetId == 0x7f && addr.Lun == 0x7f) { 1169 addr.TargetId = (UCHAR)0xff; 1170 addr.Lun = 0; 1171 printf("Resetting channel...\n"); 1172 } else { 1173 printf("Resetting device...\n"); 1174 } 1175 1176 status = ata_send_ioctl(h, &addr, "-UNIATA-", 1177 IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE, 1178 NULL, 0, 1179 NULL, 0, 1180 &returned); 1181 if(!status) { 1182 printf("Reset failed\n"); 1183 } else { 1184 printf("Channel reset done\n"); 1185 } 1186 ata_close_dev(h); 1187 return TRUE; 1188 } // end ata_reset() 1189 1190 BOOLEAN 1191 ata_hide( 1192 int bus_id, 1193 int dev_id, 1194 int lock, 1195 int persistent_hide, 1196 int power_mode 1197 ) 1198 { 1199 char dev_name[64]; 1200 HANDLE h; 1201 ULONG status; 1202 ULONG returned; 1203 SCSI_ADDRESS addr; 1204 ADDREMOVEDEV to; 1205 1206 if(dev_id == -1) { 1207 return FALSE; 1208 } 1209 1210 if(power_mode) { 1211 ata_power_mode(bus_id, dev_id, power_mode); 1212 } 1213 1214 if(lock < 0) { 1215 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT; 1216 } 1217 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id); 1218 h = ata_open_dev(dev_name); 1219 if(!h) 1220 return FALSE; 1221 addr.Length = sizeof(addr); 1222 addr.PortNumber = bus_id; 1223 addr.PathId = (UCHAR)(dev_id >> 16); 1224 addr.TargetId = (UCHAR)(dev_id >> 8); 1225 addr.Lun = (UCHAR)(dev_id); 1226 1227 to.WaitForPhysicalLink = lock; 1228 to.Flags = persistent_hide ? UNIATA_REMOVE_FLAGS_HIDE : 0; 1229 1230 printf("Deleting device.\n"); 1231 if(lock) { 1232 printf("ATTENTION: you have %d seconds to disconnect cable\n", lock); 1233 } 1234 status = ata_send_ioctl(h, &addr, "-UNIATA-", 1235 IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE, 1236 &to, sizeof(to), 1237 NULL, 0, 1238 &returned); 1239 if(!status) { 1240 printf("Delete failed\n"); 1241 } else { 1242 printf("Device is detached\n"); 1243 } 1244 ata_close_dev(h); 1245 return status ? TRUE : FALSE; 1246 } // end ata_hide() 1247 1248 BOOLEAN 1249 ata_scan( 1250 int bus_id, 1251 int dev_id, 1252 int lock, 1253 int unhide 1254 ) 1255 { 1256 char dev_name[64]; 1257 HANDLE h; 1258 ULONG status; 1259 ULONG returned; 1260 SCSI_ADDRESS addr; 1261 ADDREMOVEDEV to; 1262 1263 if(dev_id == -1) { 1264 return FALSE; 1265 } 1266 if(lock < 0) { 1267 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT; 1268 } 1269 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id); 1270 h = ata_open_dev(dev_name); 1271 if(!h) 1272 return FALSE; 1273 1274 if((UCHAR)(dev_id) != 0xff && 1275 (UCHAR)(dev_id >> 8) != 0xff) { 1276 1277 addr.Length = sizeof(addr); 1278 addr.PortNumber = bus_id; 1279 addr.PathId = (UCHAR)(dev_id >> 16); 1280 addr.TargetId = 0; 1281 addr.Lun = 0; 1282 1283 to.WaitForPhysicalLink = lock; 1284 to.Flags = unhide ? UNIATA_ADD_FLAGS_UNHIDE : 0; 1285 1286 printf("Scanning bus for new devices.\n"); 1287 if(lock) { 1288 printf("You have %d seconds to connect device.\n", lock); 1289 } 1290 status = ata_send_ioctl(h, &addr, "-UNIATA-", 1291 IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES, 1292 &to, sizeof(to), 1293 NULL, 0, 1294 &returned); 1295 } else { 1296 status = DeviceIoControl(h, 1297 IOCTL_SCSI_RESCAN_BUS, 1298 NULL, 0, 1299 NULL, 0, 1300 &returned, 1301 FALSE); 1302 } 1303 ata_close_dev(h); 1304 return status ? TRUE : FALSE; 1305 } // end ata_scan() 1306 1307 CHAR* 1308 _fgets( 1309 CHAR *string, 1310 int count, 1311 HANDLE stream 1312 ) 1313 { 1314 CHAR *pointer = string; 1315 ULONG read_bytes; 1316 1317 CHAR *retval = string; 1318 int ch = 0; 1319 1320 if (count <= 0) 1321 return(NULL); 1322 1323 while (--count) 1324 { 1325 if(!ReadFile(stream, &ch, 1, &read_bytes, NULL) || 1326 !read_bytes) 1327 { 1328 if (pointer == string) { 1329 retval=NULL; 1330 goto done; 1331 } 1332 break; 1333 } 1334 1335 if ((*pointer++ = (CHAR)ch) == '\n') { 1336 break; 1337 } 1338 } 1339 1340 *pointer = '\0'; 1341 1342 /* Common return */ 1343 done: 1344 return(retval); 1345 } // end _fgets() 1346 1347 BOOLEAN 1348 ata_bblk( 1349 int bus_id, 1350 int dev_id, 1351 int list_bb 1352 ) 1353 { 1354 char dev_name[64]; 1355 char tmp[64]; 1356 char DevSerial[128]; 1357 HANDLE h = NULL; 1358 HANDLE hf = NULL; 1359 ULONG status; 1360 ULONG returned; 1361 SCSI_ADDRESS addr; 1362 ULONG len; 1363 ULONG Length; 1364 BOOLEAN retval = FALSE; 1365 HKEY hKey2 = NULL; 1366 char* bblist = NULL; 1367 LONGLONG tmp_bb_lba; 1368 LONGLONG tmp_bb_len; 1369 char BB_Msg[256]; 1370 int radix=gRadix; 1371 int i, j; 1372 ULONG b; 1373 1374 if(dev_id == -1) { 1375 printf("\nERROR: Target device/bus ID must be specified\n\n"); 1376 print_help(); 1377 return FALSE; 1378 } 1379 if(((dev_id >> 16) & 0xff) == 0xff) { 1380 printf("\nERROR: Target device bus number (channel) must be specified with b:<bus id>\n\n"); 1381 print_help(); 1382 return FALSE; 1383 } 1384 if(((dev_id >> 8) & 0xff) == 0xff) { 1385 printf("\nERROR: Target device ID must be specified with d:<device id>\n\n"); 1386 print_help(); 1387 return FALSE; 1388 } 1389 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id); 1390 h = ata_open_dev(dev_name); 1391 if(!h) { 1392 if(bus_id == -1) { 1393 printf("Controller number must be specified\n"); 1394 } else { 1395 printf("Can't open Controller %d\n", bus_id); 1396 } 1397 return FALSE; 1398 } 1399 1400 if(list_bb == 0) { 1401 hf = ata_open_file(g_bb_list, FALSE); 1402 if(!hf) { 1403 printf("Can't open bad block list file:\n %s\n", g_bb_list); 1404 ata_close_dev(h); 1405 return FALSE; 1406 } 1407 1408 len = GetFileSize(hf, NULL); 1409 if(!len || len == INVALID_FILE_SIZE) 1410 goto exit; 1411 bblist = (char*)GlobalAlloc(GMEM_FIXED, len*8); 1412 } 1413 1414 if(!ata_check_unit(h, dev_id | (bus_id << 24))) { 1415 goto exit; 1416 } 1417 1418 hKey2 = ata_get_bblist_regh(&g_ident, DevSerial, list_bb==1); 1419 if(!hKey2) { 1420 printf("Can't open registry key:\n HKLM\\SYSTEM\\CurrentControlSet\\Services\\UniATA\\Parameters\\BadBlocks\n"); 1421 goto exit; 1422 } 1423 1424 if(list_bb == -1) { 1425 if(RegDeleteValue(hKey2, DevSerial) != ERROR_SUCCESS) { 1426 printf("Can't delete registry value:\n %s\n", DevSerial); 1427 goto exit; 1428 } 1429 1430 addr.PortNumber = bus_id; 1431 addr.PathId = (UCHAR)(dev_id >> 16); 1432 addr.TargetId = (UCHAR)(dev_id >> 8); 1433 addr.Lun = (UCHAR)(dev_id); 1434 1435 status = ata_send_ioctl(h, &addr, "-UNIATA-", 1436 IOCTL_SCSI_MINIPORT_UNIATA_RESETBB, 1437 NULL, 0, 1438 NULL, 0, 1439 &returned); 1440 if(!status) { 1441 printf("Bad block list shall be cleared after reboot.\n"); 1442 } else { 1443 printf("Bad block list cleared\n"); 1444 } 1445 } else 1446 if(list_bb == 0) { 1447 LONGLONG* pData = ((LONGLONG*)bblist); 1448 char a; 1449 int k, k0; 1450 Length=0; 1451 i=0; 1452 j=0; 1453 k=0; 1454 while(_fgets(BB_Msg, sizeof(BB_Msg), hf)) { 1455 j++; 1456 BB_Msg[sizeof(BB_Msg)-1] = 0; 1457 k=0; 1458 while((a = BB_Msg[k])) { 1459 if(a == ' ' || a == '\t' || a == '\r') { 1460 k++; 1461 continue; 1462 } 1463 break; 1464 } 1465 if(!a || a == ';' || a == '#') { 1466 continue; 1467 } 1468 if(!strncmp(BB_Msg+k, "hex:", 4)) { 1469 radix=16; 1470 continue; 1471 } 1472 if(!strncmp(BB_Msg+k, "dec:", 4)) { 1473 radix=10; 1474 continue; 1475 } 1476 k0 = k; 1477 while((a = BB_Msg[k])) { 1478 if(a == ' ' || a == '\t' || a == '\r') { 1479 BB_Msg[k] = '\t'; 1480 } 1481 k++; 1482 if(a == ';' || a == '#') { 1483 break; 1484 } 1485 if(a >= '0' && a <= '9') { 1486 continue; 1487 } 1488 if(radix == 16 && ((a >= 'A' && a <= 'F') || (a >= 'a' && a <= 'f'))) { 1489 continue; 1490 } 1491 printf("Bad input BB list file:\n %s\n", g_bb_list); 1492 printf("Illegal character '%1.1s' in line %d:\n%s\n", BB_Msg+k-1, j, BB_Msg); 1493 k0=-1; 1494 break; 1495 } 1496 if(k0 == -1) { 1497 continue; 1498 } 1499 k = k0; 1500 if(radix == 10) { 1501 b = sscanf(BB_Msg+k, "%I64u\t%I64u", &tmp_bb_lba, &tmp_bb_len); 1502 } else { 1503 b = sscanf(BB_Msg+k, "%I64x\t%I64x", &tmp_bb_lba, &tmp_bb_len); 1504 } 1505 if(b == 1) { 1506 tmp_bb_len = 1; 1507 } else 1508 if(b != 2) { 1509 printf("Bad input BB list file:\n %s\n", g_bb_list); 1510 printf("Can't parse line %d:\n%s\n", j, BB_Msg); 1511 continue; 1512 } 1513 if(!tmp_bb_len) { 1514 printf("Bad input BB list file:\n %s\n", g_bb_list); 1515 printf("BlockCount evaluated to 0 in line %d:\n%s\n", j, BB_Msg); 1516 continue; 1517 } 1518 if(tmp_bb_lba < 0) { 1519 printf("Bad input BB list file:\n %s\n", g_bb_list); 1520 printf("Start LBA evaluated to negative in line %d:\n%s\n", j, BB_Msg); 1521 continue; 1522 } 1523 if(tmp_bb_len < 0) { 1524 printf("Bad input BB list file:\n %s\n", g_bb_list); 1525 printf("BlockCount evaluated to negative in line %d:\n%s\n", j, BB_Msg); 1526 continue; 1527 } 1528 1529 if(i && 1530 (pData[(i-1)*2+1] == tmp_bb_lba)) { 1531 pData[(i-1)*2+1]+=tmp_bb_len; 1532 } else { 1533 pData[i*2+0]=tmp_bb_lba; 1534 pData[i*2+1]=tmp_bb_lba+tmp_bb_len; 1535 i++; 1536 Length += sizeof(LONGLONG)*2; 1537 } 1538 } 1539 1540 if(RegSetValueEx(hKey2, DevSerial, NULL, REG_BINARY, (const UCHAR*)bblist, Length) != ERROR_SUCCESS) { 1541 printf("Can't set registry value:\n %s\n", DevSerial); 1542 goto exit; 1543 } 1544 /* 1545 addr.PortNumber = bus_id; 1546 addr.PathId = (UCHAR)(dev_id >> 16); 1547 addr.TargetId = (UCHAR)(dev_id >> 8); 1548 addr.Lun = (UCHAR)(dev_id); 1549 1550 status = ata_send_ioctl(h, &addr, "-UNIATA-", 1551 IOCTL_SCSI_MINIPORT_UNIATA_SETBB, 1552 NULL, 0, 1553 NULL, 0, 1554 &returned); 1555 */ 1556 printf("Bad block list shall be applied after reboot\n"); 1557 } else { 1558 len = 0; 1559 returned = RegQueryValueEx(hKey2, DevSerial, NULL, NULL, NULL, &len); 1560 if(returned == 2) { 1561 printf("No bad block list assigned\n"); 1562 goto exit; 1563 } else 1564 if(returned != ERROR_SUCCESS) { 1565 printf("Can't get registry value:\n %s\n", DevSerial); 1566 goto exit; 1567 } 1568 1569 hf = ata_open_file(g_bb_list, TRUE); 1570 if(!hf) { 1571 printf("Can't create bad block list file:\n %s\n", g_bb_list); 1572 goto exit; 1573 } 1574 1575 bblist = (char*)GlobalAlloc(GMEM_FIXED, len); 1576 if(RegQueryValueEx(hKey2, DevSerial, NULL, NULL, (UCHAR*)bblist, &len) != ERROR_SUCCESS) { 1577 printf("Can't get registry value:\n %s\n", DevSerial); 1578 goto exit; 1579 } 1580 if(g_bb_list) { 1581 for (j = 0; j < 20; j += 2) { 1582 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.ModelNumber))[j]); 1583 } 1584 b = sprintf(BB_Msg, "#model: %20.20s\n", tmp); 1585 WriteFile(hf, BB_Msg, b, &returned, NULL); 1586 for (j = 0; j < 4; j += 2) { 1587 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.FirmwareRevision))[j]); 1588 } 1589 b = sprintf(BB_Msg, "#rev: %4.4s\n", tmp); 1590 WriteFile(hf, BB_Msg, b, &returned, NULL); 1591 for (j = 0; j < 20; j += 2) { 1592 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.SerialNumber))[j]); 1593 } 1594 b = sprintf(BB_Msg, "#s/n: %20.20s\n", tmp); 1595 WriteFile(hf, BB_Msg, b, &returned, NULL); 1596 b = sprintf(BB_Msg, "#%s\n", DevSerial); 1597 WriteFile(hf, BB_Msg, b, &returned, NULL); 1598 b = sprintf(BB_Msg, "#Starting LBA\tNum. of Blocks\n"); 1599 WriteFile(hf, BB_Msg, b, &returned, NULL); 1600 b = sprintf(BB_Msg, "hex:\n"); 1601 WriteFile(hf, BB_Msg, b, &returned, NULL); 1602 } else { 1603 b = sprintf(BB_Msg, "Starting LBA\tNum. of Blocks (HEX)\n"); 1604 WriteFile(hf, BB_Msg, b, &returned, NULL); 1605 } 1606 i = 0; 1607 while(len >= sizeof(LONGLONG)*2) { 1608 tmp_bb_lba = ((LONGLONG*)bblist)[i*2+0]; 1609 tmp_bb_len = ((LONGLONG*)bblist)[i*2+1] - tmp_bb_lba; 1610 b = sprintf(BB_Msg, "%I64u\t%I64u\n", tmp_bb_lba, tmp_bb_len); 1611 WriteFile(hf, BB_Msg, b, &returned, NULL); 1612 i++; 1613 len -= sizeof(LONGLONG)*2; 1614 } 1615 } 1616 retval = TRUE; 1617 exit: 1618 if(hKey2) 1619 RegCloseKey(hKey2); 1620 if(bblist) { 1621 GlobalFree(bblist); 1622 } 1623 ata_close_dev(hf); 1624 ata_close_dev(h); 1625 return retval; 1626 } // end ata_bblk() 1627 1628 BOOLEAN 1629 ata_power_mode( 1630 int bus_id, 1631 int dev_id, 1632 int power_mode 1633 ) 1634 { 1635 char dev_name[64]; 1636 HANDLE h; 1637 ULONG status; 1638 ULONG returned; 1639 SCSI_ADDRESS addr; 1640 CDB cdb; 1641 SENSE_DATA senseData; 1642 1643 if(dev_id == -1) { 1644 return FALSE; 1645 } 1646 if(!power_mode) { 1647 return TRUE; 1648 } 1649 1650 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id); 1651 h = ata_open_dev(dev_name); 1652 if(!h) 1653 return FALSE; 1654 addr.PortNumber = bus_id; 1655 addr.PathId = (UCHAR)(dev_id >> 16); 1656 addr.TargetId = (UCHAR)(dev_id >> 8); 1657 addr.Lun = (UCHAR)(dev_id); 1658 1659 memset(&cdb, 0, sizeof(cdb)); 1660 cdb.START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 1661 cdb.START_STOP.Immediate = 1; 1662 cdb.START_STOP.PowerConditions = power_mode; 1663 cdb.START_STOP.Start = (power_mode != StartStop_Power_Sleep); 1664 1665 printf("Changing power state to ...\n"); 1666 1667 status = ata_send_scsi(h, &addr, &cdb, 6, 1668 NULL, 0, FALSE, 1669 &senseData, &returned); 1670 ata_close_dev(h); 1671 return status ? TRUE : FALSE; 1672 } // end ata_power_mode() 1673 1674 int 1675 ata_num_to_x_dev( 1676 char a 1677 ) 1678 { 1679 if(a >= '0' && a <= '9') 1680 return a-'0'; 1681 return -1; 1682 } 1683 1684 int 1685 main ( 1686 int argc, 1687 char* argv[] 1688 ) 1689 { 1690 //ULONG Flags = 0; 1691 int i; 1692 uintptr_t j; 1693 char a; 1694 int bus_id = -1; 1695 int dev_id = -1; 1696 int cmd = 0; 1697 int lock = -1; 1698 int b_dev=-1, d_dev=-1, l_dev=0; 1699 int mode=-1; 1700 int list_bb=0; 1701 int persistent_hide=0; 1702 int power_mode=StartStop_Power_NoChg; 1703 1704 printf("Console ATA control utility for Windows NT3.51/NT4/2000/XP/2003\n" 1705 "Version 0." UNIATA_VER_STR ", Copyright (c) Alexander A. Telyatnikov, 2003-2012\n" 1706 "Home site: http://alter.org.ua\n"); 1707 1708 for(i=1; i<argc; i++) { 1709 if(!argv[i]) 1710 continue; 1711 if((a = argv[i][0]) != '-') { 1712 for(j=0; (a = argv[i][j]); j++) { 1713 switch(a) { 1714 case 'a' : 1715 case 's' : 1716 case 'c' : 1717 j++; 1718 bus_id = ata_num_to_x_dev(argv[i][j]); 1719 break; 1720 case 'b' : 1721 j++; 1722 b_dev = ata_num_to_x_dev(argv[i][j]); 1723 break; 1724 case 'd' : 1725 j++; 1726 d_dev = ata_num_to_x_dev(argv[i][j]); 1727 break; 1728 case 'l' : 1729 j++; 1730 l_dev = ata_num_to_x_dev(argv[i][j]); 1731 break; 1732 case ':' : 1733 break; 1734 default: 1735 print_help(); 1736 } 1737 } 1738 continue; 1739 } 1740 j=1; 1741 while(argv[i] && (a = argv[i][j]) && (a != ' ') && (a != '\t')) { 1742 switch(a) { 1743 case 'l' : 1744 if(cmd || lock>0) { 1745 print_help(); 1746 } 1747 cmd = CMD_ATA_LIST; 1748 break; 1749 case 'x' : 1750 g_extended = 1; 1751 break; 1752 case 'a' : 1753 g_adapter_info = 1; 1754 break; 1755 case 'S' : 1756 persistent_hide = 1; 1757 case 's' : 1758 if(cmd || lock>0) { 1759 print_help(); 1760 } 1761 cmd = CMD_ATA_FIND; 1762 d_dev = 0; 1763 break; 1764 case 'H' : 1765 persistent_hide = 1; 1766 case 'h' : 1767 if(cmd) { 1768 print_help(); 1769 } 1770 cmd = CMD_ATA_HIDE; 1771 d_dev = 0; 1772 break; 1773 case 'm' : 1774 if(cmd) { 1775 print_help(); 1776 } 1777 cmd = CMD_ATA_MODE; 1778 i++; 1779 if(!argv[i]) { 1780 print_help(); 1781 } 1782 mode = ata_str_to_mode(argv[i]); 1783 if(mode == -1) { 1784 i--; 1785 } else { 1786 j = strlen(argv[i])-1; 1787 } 1788 break; 1789 case 'r' : 1790 if(cmd) { 1791 print_help(); 1792 } 1793 cmd = CMD_ATA_RESET; 1794 break; 1795 case 'b' : 1796 if(cmd) { 1797 print_help(); 1798 } 1799 switch(argv[i][j+1]) { 1800 case 'l': 1801 list_bb = 1; 1802 break; 1803 case 'a': 1804 list_bb = 0; 1805 break; 1806 case 'r': 1807 list_bb = -1; 1808 break; 1809 default: 1810 j--; 1811 } 1812 j++; 1813 cmd = CMD_ATA_BBLK; 1814 break; 1815 case 'f' : 1816 if(cmd != CMD_ATA_BBLK) { 1817 print_help(); 1818 } 1819 i++; 1820 if(!argv[i]) { 1821 print_help(); 1822 } 1823 g_bb_list=argv[i]; 1824 j = strlen(argv[i])-1; 1825 break; 1826 case 'p' : 1827 if(cmd && (cmd != CMD_ATA_FIND) && (cmd != CMD_ATA_HIDE)) { 1828 print_help(); 1829 } 1830 switch(argv[i][j+1]) { 1831 case '0': 1832 case 'a': 1833 // do nothing 1834 break; 1835 case '1': 1836 case 'i': 1837 power_mode = StartStop_Power_Idle; 1838 break; 1839 case '2': 1840 case 's': 1841 power_mode = StartStop_Power_Standby; 1842 break; 1843 case '3': 1844 case 'p': 1845 power_mode = StartStop_Power_Sleep; 1846 break; 1847 default: 1848 j--; 1849 } 1850 j++; 1851 if(power_mode && !cmd) { 1852 cmd = CMD_ATA_POWER; 1853 } 1854 break; 1855 case 'D' : 1856 power_mode = StartStop_Power_Sleep; 1857 if(cmd && (cmd != CMD_ATA_HIDE)) { 1858 print_help(); 1859 } 1860 case 'd' : 1861 if(cmd && (cmd != CMD_ATA_FIND) && (cmd != CMD_ATA_HIDE) && (cmd != CMD_ATA_POWER)) { 1862 print_help(); 1863 } 1864 if(!cmd) { 1865 cmd = CMD_ATA_HIDE; 1866 } 1867 i++; 1868 if(!argv[i]) { 1869 print_help(); 1870 } 1871 if(!sscanf(argv[i], "%d", &lock)) { 1872 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT; 1873 i--; 1874 } 1875 j = strlen(argv[i])-1; 1876 break; 1877 case 'n' : 1878 if(cmd != CMD_ATA_BBLK) { 1879 print_help(); 1880 } 1881 i++; 1882 if(!argv[i]) { 1883 print_help(); 1884 } 1885 if(!strcmp(argv[i], "hex") || 1886 !strcmp(argv[i], "16")) { 1887 gRadix = 16; 1888 } else 1889 if(!strcmp(argv[i], "dec") || 1890 !strcmp(argv[i], "10")) { 1891 gRadix = 10; 1892 } else { 1893 print_help(); 1894 } 1895 j = strlen(argv[i])-1; 1896 break; 1897 case '?' : 1898 default: 1899 print_help(); 1900 } 1901 j++; 1902 } 1903 } 1904 1905 if(g_adapter_info && !cmd) { 1906 cmd = CMD_ATA_LIST; 1907 b_dev = 127; 1908 d_dev = 127; 1909 l_dev = 127; 1910 } else 1911 if((d_dev == -1) && (b_dev != -1)) { 1912 d_dev = 127; 1913 l_dev = 127; 1914 } 1915 1916 if((d_dev != -1) && (b_dev != -1)) { 1917 dev_id = (b_dev << 16) | (d_dev << 8) | l_dev; 1918 } 1919 if(cmd == CMD_ATA_LIST) { 1920 ata_list(bus_id, dev_id); 1921 } else 1922 if(cmd == CMD_ATA_MODE) { 1923 ata_mode(bus_id, dev_id, mode); 1924 } else 1925 if(cmd == CMD_ATA_RESET) { 1926 ata_reset(bus_id, dev_id); 1927 } else 1928 if(cmd == CMD_ATA_FIND) { 1929 ata_scan(bus_id, dev_id, lock, persistent_hide); 1930 } else 1931 if(cmd == CMD_ATA_HIDE) { 1932 ata_hide(bus_id, dev_id, lock, persistent_hide, power_mode); 1933 } else 1934 if(cmd == CMD_ATA_BBLK) { 1935 ata_bblk(bus_id, dev_id, list_bb); 1936 } else 1937 if(cmd == CMD_ATA_POWER) { 1938 ata_power_mode(bus_id, dev_id, power_mode); 1939 } else { 1940 print_help(); 1941 } 1942 exit(0); 1943 } 1944 1945