[NtUser]
[reactos.git] / reactos / base / applications / atactl / atactl.cpp
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 safity\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 desing 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 int 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("Scaning 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, j;
1692 char a;
1693 int bus_id = -1;
1694 int dev_id = -1;
1695 int cmd = 0;
1696 int lock = -1;
1697 int b_dev=-1, d_dev=-1, l_dev=0;
1698 int mode=-1;
1699 int list_bb=0;
1700 int persistent_hide=0;
1701 int power_mode=StartStop_Power_NoChg;
1702
1703 printf("Console ATA control utility for Windows NT3.51/NT4/2000/XP/2003\n"
1704 "Version 0." UNIATA_VER_STR ", Copyright (c) Alexander A. Telyatnikov, 2003-2012\n"
1705 "Home site: http://alter.org.ua\n");
1706
1707 for(i=1; i<argc; i++) {
1708 if(!argv[i])
1709 continue;
1710 if((a = argv[i][0]) != '-') {
1711 for(j=0; (a = argv[i][j]); j++) {
1712 switch(a) {
1713 case 'a' :
1714 case 's' :
1715 case 'c' :
1716 j++;
1717 bus_id = ata_num_to_x_dev(argv[i][j]);
1718 break;
1719 case 'b' :
1720 j++;
1721 b_dev = ata_num_to_x_dev(argv[i][j]);
1722 break;
1723 case 'd' :
1724 j++;
1725 d_dev = ata_num_to_x_dev(argv[i][j]);
1726 break;
1727 case 'l' :
1728 j++;
1729 l_dev = ata_num_to_x_dev(argv[i][j]);
1730 break;
1731 case ':' :
1732 break;
1733 default:
1734 print_help();
1735 }
1736 }
1737 continue;
1738 }
1739 j=1;
1740 while(argv[i] && (a = argv[i][j]) && (a != ' ') && (a != '\t')) {
1741 switch(a) {
1742 case 'l' :
1743 if(cmd || lock>0) {
1744 print_help();
1745 }
1746 cmd = CMD_ATA_LIST;
1747 break;
1748 case 'x' :
1749 g_extended = 1;
1750 break;
1751 case 'a' :
1752 g_adapter_info = 1;
1753 break;
1754 case 'S' :
1755 persistent_hide = 1;
1756 case 's' :
1757 if(cmd || lock>0) {
1758 print_help();
1759 }
1760 cmd = CMD_ATA_FIND;
1761 d_dev = 0;
1762 break;
1763 case 'H' :
1764 persistent_hide = 1;
1765 case 'h' :
1766 if(cmd) {
1767 print_help();
1768 }
1769 cmd = CMD_ATA_HIDE;
1770 d_dev = 0;
1771 break;
1772 case 'm' :
1773 if(cmd) {
1774 print_help();
1775 }
1776 cmd = CMD_ATA_MODE;
1777 i++;
1778 if(!argv[i]) {
1779 print_help();
1780 }
1781 mode = ata_str_to_mode(argv[i]);
1782 if(mode == -1) {
1783 i--;
1784 } else {
1785 j = strlen(argv[i])-1;
1786 }
1787 break;
1788 case 'r' :
1789 if(cmd) {
1790 print_help();
1791 }
1792 cmd = CMD_ATA_RESET;
1793 break;
1794 case 'b' :
1795 if(cmd) {
1796 print_help();
1797 }
1798 switch(argv[i][j+1]) {
1799 case 'l':
1800 list_bb = 1;
1801 break;
1802 case 'a':
1803 list_bb = 0;
1804 break;
1805 case 'r':
1806 list_bb = -1;
1807 break;
1808 default:
1809 j--;
1810 }
1811 j++;
1812 cmd = CMD_ATA_BBLK;
1813 break;
1814 case 'f' :
1815 if(cmd != CMD_ATA_BBLK) {
1816 print_help();
1817 }
1818 i++;
1819 if(!argv[i]) {
1820 print_help();
1821 }
1822 g_bb_list=argv[i];
1823 j = strlen(argv[i])-1;
1824 break;
1825 case 'p' :
1826 if(cmd && (cmd != CMD_ATA_FIND) && (cmd != CMD_ATA_HIDE)) {
1827 print_help();
1828 }
1829 switch(argv[i][j+1]) {
1830 case '0':
1831 case 'a':
1832 // do nothing
1833 break;
1834 case '1':
1835 case 'i':
1836 power_mode = StartStop_Power_Idle;
1837 break;
1838 case '2':
1839 case 's':
1840 power_mode = StartStop_Power_Standby;
1841 break;
1842 case '3':
1843 case 'p':
1844 power_mode = StartStop_Power_Sleep;
1845 break;
1846 default:
1847 j--;
1848 }
1849 j++;
1850 if(power_mode && !cmd) {
1851 cmd = CMD_ATA_POWER;
1852 }
1853 break;
1854 case 'D' :
1855 power_mode = StartStop_Power_Sleep;
1856 if(cmd && (cmd != CMD_ATA_HIDE)) {
1857 print_help();
1858 }
1859 case 'd' :
1860 if(cmd && (cmd != CMD_ATA_FIND) && (cmd != CMD_ATA_HIDE) && (cmd != CMD_ATA_POWER)) {
1861 print_help();
1862 }
1863 if(!cmd) {
1864 cmd = CMD_ATA_HIDE;
1865 }
1866 i++;
1867 if(!argv[i]) {
1868 print_help();
1869 }
1870 if(!sscanf(argv[i], "%d", &lock)) {
1871 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
1872 i--;
1873 }
1874 j = strlen(argv[i])-1;
1875 break;
1876 case 'n' :
1877 if(cmd != CMD_ATA_BBLK) {
1878 print_help();
1879 }
1880 i++;
1881 if(!argv[i]) {
1882 print_help();
1883 }
1884 if(!strcmp(argv[i], "hex") ||
1885 !strcmp(argv[i], "16")) {
1886 gRadix = 16;
1887 } else
1888 if(!strcmp(argv[i], "dec") ||
1889 !strcmp(argv[i], "10")) {
1890 gRadix = 10;
1891 } else {
1892 print_help();
1893 }
1894 j = strlen(argv[i])-1;
1895 break;
1896 case '?' :
1897 default:
1898 print_help();
1899 }
1900 j++;
1901 }
1902 }
1903
1904 if(g_adapter_info && !cmd) {
1905 cmd = CMD_ATA_LIST;
1906 b_dev = 127;
1907 d_dev = 127;
1908 l_dev = 127;
1909 } else
1910 if((d_dev == -1) && (b_dev != -1)) {
1911 d_dev = 127;
1912 l_dev = 127;
1913 }
1914
1915 if((d_dev != -1) && (b_dev != -1)) {
1916 dev_id = (b_dev << 16) | (d_dev << 8) | l_dev;
1917 }
1918 if(cmd == CMD_ATA_LIST) {
1919 ata_list(bus_id, dev_id);
1920 } else
1921 if(cmd == CMD_ATA_MODE) {
1922 ata_mode(bus_id, dev_id, mode);
1923 } else
1924 if(cmd == CMD_ATA_RESET) {
1925 ata_reset(bus_id, dev_id);
1926 } else
1927 if(cmd == CMD_ATA_FIND) {
1928 ata_scan(bus_id, dev_id, lock, persistent_hide);
1929 } else
1930 if(cmd == CMD_ATA_HIDE) {
1931 ata_hide(bus_id, dev_id, lock, persistent_hide, power_mode);
1932 } else
1933 if(cmd == CMD_ATA_BBLK) {
1934 ata_bblk(bus_id, dev_id, list_bb);
1935 } else
1936 if(cmd == CMD_ATA_POWER) {
1937 ata_power_mode(bus_id, dev_id, power_mode);
1938 } else {
1939 print_help();
1940 }
1941 exit(0);
1942 }
1943