* Slap *some* sense into our header inclusions.
[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 PCHAR 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.PortNumber = -1;
731 addr.PathId = inquiryData->PathId;
732 addr.TargetId = inquiryData->TargetId;
733 addr.Lun = inquiryData->Lun;
734 status = ata_send_ioctl(h, &addr, (PCHAR)"-UNIATA-",
735 IOCTL_SCSI_MINIPORT_UNIATA_GET_MODE,
736 NULL, 0,
737 &IoMode, sizeof(IoMode),
738 &returned);
739 if(status) {
740 //io_mode = min(IoMode.CurrentMode, IoMode.MaxMode);
741 io_mode = IoMode.PhyMode;
742 if(!io_mode) {
743 io_mode = min(max(IoMode.CurrentMode,IoMode.OrigMode),IoMode.MaxMode);
744 }
745 } else {
746 io_mode = -1;
747 }
748
749 memset(&pin, 0, sizeof(pin));
750 memset(buff, 0, sizeof(buff));
751 pin.irDriveRegs.bCommandReg = ID_CMD;
752 // this is valid for IDE/ATA, where only 2 devices can be attached to the bus.
753 // probably, we shall change this in future to support SATA splitters
754 pin.bDriveNumber = inquiryData->PathId*2+inquiryData->TargetId;
755
756 status = ata_send_ioctl(h, NULL, (PCHAR)"SCSIDISK",
757 IOCTL_SCSI_MINIPORT_IDENTIFY,
758 &pin, sizeof(pin),
759 buff, sizeof(buff),
760 &returned);
761
762 if(!status) {
763 memset(&pin, 0, sizeof(pin));
764 memset(buff, 0, sizeof(buff));
765 pin.irDriveRegs.bCommandReg = ATAPI_ID_CMD;
766 // this is valid for IDE/ATA, where only 2 devices can be attached to the bus.
767 // probably, we shall change this in future to support SATA splitters
768 pin.bDriveNumber = inquiryData->PathId*2+inquiryData->TargetId;
769
770 status = ata_send_ioctl(h, NULL, (PCHAR)"SCSIDISK",
771 IOCTL_SCSI_MINIPORT_IDENTIFY,
772 &pin, sizeof(pin),
773 buff, sizeof(buff),
774 &returned);
775
776 }
777
778 if(!g_extended) {
779 printf(" b%lu:d%d%s %24.24s %4.4s ",
780 i,
781 inquiryData->TargetId,
782 lun_str,
783 /*(inquiryData->DeviceClaimed) ? "Y" : "N",*/
784 (g_extended ? (PUCHAR)"" : &scsi_ident->VendorId[0]),
785 (g_extended ? (PUCHAR)"" : &scsi_ident->ProductRevisionLevel[0])
786 );
787 } else {
788 printf(" b%lu:d%d%s ",
789 i,
790 inquiryData->TargetId,
791 lun_str
792 );
793 }
794
795 if(status) {
796 if(io_mode == -1) {
797 io_mode = ata_cur_mode_from_ident(ident, IDENT_MODE_ACTIVE);
798 }
799 }
800 if(io_mode != -1) {
801 ata_mode_to_str(mode_str, io_mode);
802 }
803 if(!g_extended || !status) {
804 if(g_extended) {
805 printf(" %24.24s %4.4s ",
806 (&inquiryData->InquiryData[8]),
807 (&inquiryData->InquiryData[8+24])
808 );
809 }
810 if(io_mode != -1) {
811 printf(" %.12s ", mode_str);
812 }
813 }
814 printf("\n");
815
816 if(g_extended) {
817 if(status) {
818
819 BOOLEAN BlockMode_valid = TRUE;
820 BOOLEAN print_geom = FALSE;
821
822 switch(ident->DeviceType) {
823 case ATAPI_TYPE_DIRECT:
824 if(ident->Removable) {
825 printf(" Floppy ");
826 } else {
827 printf(" Hard Drive ");
828 }
829 break;
830 case ATAPI_TYPE_TAPE:
831 printf(" Tape Drive ");
832 break;
833 case ATAPI_TYPE_CDROM:
834 printf(" CD/DVD Drive ");
835 BlockMode_valid = FALSE;
836 break;
837 case ATAPI_TYPE_OPTICAL:
838 printf(" Optical Drive ");
839 BlockMode_valid = FALSE;
840 break;
841 default:
842 printf(" Hard Drive ");
843 print_geom = TRUE;
844 //MOV_DD_SWP(max_lba, ident->UserAddressableSectors);
845 max_lba = ident->UserAddressableSectors;
846 if(ident->FeaturesSupport.Address48) {
847 max_lba = ident->UserAddressableSectors48;
848 }
849 //MOV_DW_SWP(chs[0], ident->NumberOfCylinders);
850 //MOV_DW_SWP(chs[1], ident->NumberOfHeads);
851 //MOV_DW_SWP(chs[2], ident->SectorsPerTrack);
852 chs[0] = ident->NumberOfCylinders;
853 chs[1] = ident->NumberOfHeads;
854 chs[2] = ident->SectorsPerTrack;
855 if(!max_lba) {
856 max_lba = (ULONG)(chs[0])*(ULONG)(chs[1])*(ULONG)(chs[2]);
857 }
858 }
859 if(io_mode != -1) {
860 printf(" %.12s\n", mode_str);
861 }
862 for (j = 0; j < 40; j += 2) {
863 MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->ModelNumber)[j]);
864 }
865 printf(" Mod: %40.40s\n", SerNum);
866 for (j = 0; j < 8; j += 2) {
867 MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->FirmwareRevision)[j]);
868 }
869 printf(" Rev: %8.8s\n", SerNum);
870 for (j = 0; j < 20; j += 2) {
871 MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->SerialNumber)[j]);
872 }
873 printf(" S/N: %20.20s\n", SerNum);
874
875 if(BlockMode_valid) {
876 if(ident->MaximumBlockTransfer) {
877 printf(" Multi-block mode: %u block%s\n", ident->MaximumBlockTransfer, ident->MaximumBlockTransfer == 1 ? "" : "s");
878 } else {
879 printf(" Multi-block mode: N/A\n");
880 }
881 }
882 if(print_geom) {
883 printf(" C/H/S: %u/%u/%u \n", chs[0], chs[1], chs[2]);
884 printf(" LBA: %I64u \n", max_lba);
885 if(max_lba < 2) {
886 printf(" Size: %lu kb\n", (ULONG)(max_lba/2));
887 } else
888 if(max_lba < 2*1024*1024) {
889 printf(" Size: %lu Mb\n", (ULONG)(max_lba/2048));
890 } else
891 if(max_lba < (ULONG)2*1024*1024*1024) {
892 printf(" Size: %lu.%lu (%lu) Gb\n", (ULONG)(max_lba/2048/1024),
893 (ULONG)(((max_lba/2048)%1024)/10),
894 (ULONG)(max_lba*512/1000/1000/1000)
895 );
896 } else {
897 printf(" Size: %lu.%lu (%lu) Tb\n", (ULONG)(max_lba/2048/1024/1024),
898 (ULONG)((max_lba/2048/1024)%1024)/10,
899 (ULONG)(max_lba*512/1000/1000/1000)
900 );
901 }
902 }
903 len = 0;
904 if((hKey2 = ata_get_bblist_regh(ident, DevSerial, TRUE))) {
905 if(RegQueryValueEx(hKey2, DevSerial, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
906 printf(" !!! Assigned bad-block list !!!\n");
907 }
908 RegCloseKey(hKey2);
909 }
910 } else {
911 switch(scsi_ident->DeviceType) {
912 case DIRECT_ACCESS_DEVICE:
913 if(scsi_ident->RemovableMedia) {
914 printf(" Floppy ");
915 } else {
916 printf(" Hard Drive ");
917 }
918 break;
919 case SEQUENTIAL_ACCESS_DEVICE:
920 printf(" Tape Drive ");
921 break;
922 case PRINTER_DEVICE:
923 printf(" Printer ");
924 break;
925 case PROCESSOR_DEVICE:
926 printf(" Processor ");
927 break;
928 case WRITE_ONCE_READ_MULTIPLE_DEVICE:
929 printf(" WORM Drive ");
930 break;
931 case READ_ONLY_DIRECT_ACCESS_DEVICE:
932 printf(" CDROM Drive ");
933 break;
934 case SCANNER_DEVICE:
935 printf(" Scanner ");
936 break;
937 case OPTICAL_DEVICE:
938 printf(" Optical Drive ");
939 break;
940 case MEDIUM_CHANGER:
941 printf(" Changer ");
942 break;
943 case COMMUNICATION_DEVICE:
944 printf(" Comm. device ");
945 break;
946 }
947 printf("\n");
948 }
949 }
950 memcpy(&g_ident, ident, sizeof(IDENTIFY_DATA));
951 }
952 next_dev:
953 if (inquiryData->NextInquiryDataOffset == 0) {
954 break;
955 }
956
957 inquiryData = (PSCSI_INQUIRY_DATA) (g_inquiry_buffer +
958 inquiryData->NextInquiryDataOffset);
959 }
960 }
961 if(!found) {
962 printf(" No device(s) found.\n");
963 return FALSE;
964 }
965
966 return TRUE;
967 } // end ata_check_unit()
968
969 BOOLEAN
970 ata_adapter_info(
971 int bus_id,
972 int print_info
973 )
974 {
975 char dev_name[64];
976 HANDLE h;
977 PADAPTERINFO AdapterInfo;
978 ULONG status;
979 ULONG returned;
980 SCSI_ADDRESS addr;
981 PCI_SLOT_NUMBER slotData;
982 char mode_str[12];
983 ULONG len;
984
985 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
986 h = ata_open_dev(dev_name);
987 if(!h)
988 return FALSE;
989 addr.PortNumber = bus_id;
990
991 len = sizeof(ADAPTERINFO)+sizeof(CHANINFO)*AHCI_MAX_PORT;
992 if(!g_AdapterInfo) {
993 AdapterInfo = (PADAPTERINFO)GlobalAlloc(GMEM_FIXED, len);
994 if(!AdapterInfo) {
995 return FALSE;
996 }
997 } else {
998 AdapterInfo = g_AdapterInfo;
999 }
1000 memset(AdapterInfo, 0, len);
1001
1002 status = ata_send_ioctl(h, &addr, (PCHAR)"-UNIATA-",
1003 IOCTL_SCSI_MINIPORT_UNIATA_ADAPTER_INFO,
1004 AdapterInfo, len,
1005 AdapterInfo, len,
1006 &returned);
1007 if(status) {
1008 ata_mode_to_str(mode_str, AdapterInfo->MaxTransferMode);
1009 }
1010 printf("Scsi%d: %s %s\n", bus_id, status ? "[UniATA]" : "", status ? mode_str : "");
1011 if(print_info) {
1012 if(!status) {
1013 printf("Can't get adapter info\n");
1014 } else {
1015 if(AdapterInfo->AdapterInterfaceType == PCIBus) {
1016 slotData.u.AsULONG = AdapterInfo->slotNumber;
1017 printf(" PCI Bus/Dev/Func: %lu/%lu/%lu%s\n",
1018 AdapterInfo->SystemIoBusNumber, slotData.u.bits.DeviceNumber, slotData.u.bits.FunctionNumber,
1019 AdapterInfo->AdapterInterfaceType == AdapterInfo->OrigAdapterInterfaceType ? "" : " (ISA-Bridged)");
1020 printf(" VendorId/DevId/Rev: %#04x/%#04x/%#02x\n",
1021 (USHORT)(AdapterInfo->DevID >> 16),
1022 (USHORT)(AdapterInfo->DevID & 0xffff),
1023 (UCHAR)(AdapterInfo->RevID));
1024 if(AdapterInfo->DeviceName[0]) {
1025 printf(" Name: %s\n", AdapterInfo->DeviceName);
1026 }
1027 } else
1028 if(AdapterInfo->AdapterInterfaceType == Isa) {
1029 printf(" ISA Bus\n");
1030 }
1031 printf(" IRQ: %ld\n", AdapterInfo->BusInterruptLevel);
1032 }
1033 }
1034 ata_close_dev(h);
1035 //GlobalFree(AdapterInfo);
1036 g_AdapterInfo = AdapterInfo;
1037 return status ? TRUE : FALSE;
1038 } // end ata_adapter_info()
1039
1040 int
1041 ata_check_controller(
1042 HANDLE h, // handle to ScsiXXX:
1043 PIO_SCSI_CAPABILITIES capabilities
1044 )
1045 {
1046 ULONG status;
1047 ULONG returned;
1048
1049 status = DeviceIoControl(h,
1050 IOCTL_SCSI_GET_CAPABILITIES,
1051 NULL,
1052 0,
1053 capabilities,
1054 sizeof(IO_SCSI_CAPABILITIES),
1055 &returned,
1056 FALSE);
1057 return status;
1058 } // end ata_check_controller()
1059
1060 BOOLEAN
1061 ata_list(
1062 int bus_id,
1063 int dev_id
1064 )
1065 {
1066 char dev_name[64];
1067 HANDLE h;
1068 BOOLEAN uniata_driven;
1069
1070 if(bus_id == -1) {
1071 for(bus_id=0; TRUE; bus_id++) {
1072 if(!ata_list(bus_id, dev_id))
1073 break;
1074 }
1075 return TRUE;
1076 }
1077 uniata_driven = ata_adapter_info(bus_id, g_adapter_info);
1078 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1079 h = ata_open_dev(dev_name);
1080 if(!h)
1081 return FALSE;
1082 if(dev_id == -1) {
1083 ata_check_controller(h, &g_capabilities);
1084 ata_check_unit(h, -1);
1085 ata_close_dev(h);
1086 return TRUE;
1087 }
1088 ata_check_unit(h, dev_id | (bus_id << 24));
1089 ata_close_dev(h);
1090 return TRUE;
1091 } // end ata_list()
1092
1093 BOOLEAN
1094 ata_mode(
1095 int bus_id,
1096 int dev_id,
1097 int mode
1098 )
1099 {
1100 char dev_name[64];
1101 HANDLE h;
1102 SETTRANSFERMODE IoMode;
1103 ULONG status;
1104 ULONG returned;
1105 SCSI_ADDRESS addr;
1106
1107 if(dev_id == -1) {
1108 return FALSE;
1109 }
1110 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1111 h = ata_open_dev(dev_name);
1112 if(!h)
1113 return FALSE;
1114 addr.PortNumber = bus_id;
1115 addr.PathId = (UCHAR)(dev_id >> 16);
1116 addr.TargetId = (UCHAR)(dev_id >> 8);
1117 addr.Lun = (UCHAR)(dev_id);
1118
1119 IoMode.MaxMode = mode;
1120 IoMode.ApplyImmediately = FALSE;
1121 // IoMode.ApplyImmediately = TRUE;
1122 IoMode.OrigMode = mode;
1123
1124 status = ata_send_ioctl(h, &addr, (PCHAR)"-UNIATA-",
1125 IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE,
1126 &IoMode, sizeof(IoMode),
1127 NULL, 0,
1128 &returned);
1129 if(!status) {
1130 printf("Can't apply specified transfer mode\n");
1131 } else {
1132 ata_mode_to_str(dev_name, mode);
1133 printf("Transfer rate switched to %s\n", dev_name);
1134 }
1135 ata_close_dev(h);
1136 return status ? TRUE : FALSE;
1137 } // end ata_mode()
1138
1139 BOOLEAN
1140 ata_reset(
1141 int bus_id,
1142 int dev_id
1143 )
1144 {
1145 char dev_name[64];
1146 HANDLE h;
1147 ULONG status;
1148 ULONG returned;
1149 SCSI_ADDRESS addr;
1150
1151 if(dev_id == -1) {
1152 return FALSE;
1153 }
1154 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1155 h = ata_open_dev(dev_name);
1156 if(!h)
1157 return FALSE;
1158 addr.PortNumber = bus_id;
1159 addr.PathId = (UCHAR)(dev_id >> 16);
1160 addr.TargetId = (UCHAR)(dev_id >> 8);
1161 addr.Lun = (UCHAR)(dev_id);
1162
1163 if(addr.TargetId == 0x7f && addr.Lun == 0x7f) {
1164 addr.TargetId = (UCHAR)0xff;
1165 addr.Lun = 0;
1166 printf("Resetting channel...\n");
1167 } else {
1168 printf("Resetting device...\n");
1169 }
1170
1171 status = ata_send_ioctl(h, &addr, "-UNIATA-",
1172 IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE,
1173 NULL, 0,
1174 NULL, 0,
1175 &returned);
1176 if(!status) {
1177 printf("Reset failed\n");
1178 } else {
1179 printf("Channel reset done\n");
1180 }
1181 ata_close_dev(h);
1182 return TRUE;
1183 } // end ata_reset()
1184
1185 BOOLEAN
1186 ata_hide(
1187 int bus_id,
1188 int dev_id,
1189 int lock,
1190 int persistent_hide,
1191 int power_mode
1192 )
1193 {
1194 char dev_name[64];
1195 HANDLE h;
1196 ULONG status;
1197 ULONG returned;
1198 SCSI_ADDRESS addr;
1199 ADDREMOVEDEV to;
1200
1201 if(dev_id == -1) {
1202 return FALSE;
1203 }
1204
1205 if(power_mode) {
1206 ata_power_mode(bus_id, dev_id, power_mode);
1207 }
1208
1209 if(lock < 0) {
1210 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
1211 }
1212 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1213 h = ata_open_dev(dev_name);
1214 if(!h)
1215 return FALSE;
1216 addr.PortNumber = bus_id;
1217 addr.PathId = (UCHAR)(dev_id >> 16);
1218 addr.TargetId = (UCHAR)(dev_id >> 8);
1219 addr.Lun = (UCHAR)(dev_id);
1220
1221 to.WaitForPhysicalLink = lock;
1222 to.Flags = persistent_hide ? UNIATA_REMOVE_FLAGS_HIDE : 0;
1223
1224 printf("Deleting device.\n");
1225 if(lock) {
1226 printf("ATTENTION: you have %d seconds to disconnect cable\n", lock);
1227 }
1228 status = ata_send_ioctl(h, &addr, (PCHAR)"-UNIATA-",
1229 IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE,
1230 &to, sizeof(to),
1231 NULL, 0,
1232 &returned);
1233 ata_close_dev(h);
1234 return TRUE;
1235 } // end ata_hide()
1236
1237 BOOLEAN
1238 ata_scan(
1239 int bus_id,
1240 int dev_id,
1241 int lock,
1242 int unhide
1243 )
1244 {
1245 char dev_name[64];
1246 HANDLE h;
1247 ULONG status;
1248 ULONG returned;
1249 SCSI_ADDRESS addr;
1250 ADDREMOVEDEV to;
1251
1252 if(dev_id == -1) {
1253 return FALSE;
1254 }
1255 if(lock < 0) {
1256 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
1257 }
1258 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1259 h = ata_open_dev(dev_name);
1260 if(!h)
1261 return FALSE;
1262
1263 if((UCHAR)(dev_id) != 0xff &&
1264 (UCHAR)(dev_id >> 8) != 0xff) {
1265
1266 addr.PortNumber = bus_id;
1267 addr.PathId = (UCHAR)(dev_id >> 16);
1268 addr.TargetId = 0;
1269 addr.Lun = 0;
1270
1271 to.WaitForPhysicalLink = lock;
1272 to.Flags = unhide ? UNIATA_ADD_FLAGS_UNHIDE : 0;
1273
1274 printf("Scaning bus for new devices.\n");
1275 if(lock) {
1276 printf("You have %d seconds to connect device.\n", lock);
1277 }
1278 status = ata_send_ioctl(h, &addr, (PCHAR)"-UNIATA-",
1279 IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES,
1280 &to, sizeof(to),
1281 NULL, 0,
1282 &returned);
1283 } else {
1284 status = DeviceIoControl(h,
1285 IOCTL_SCSI_RESCAN_BUS,
1286 NULL, 0,
1287 NULL, 0,
1288 &returned,
1289 FALSE);
1290 }
1291 ata_close_dev(h);
1292 return TRUE;
1293 } // end ata_scan()
1294
1295 CHAR*
1296 _fgets(
1297 CHAR *string,
1298 int count,
1299 HANDLE stream
1300 )
1301 {
1302 CHAR *pointer = string;
1303 ULONG read_bytes;
1304
1305 CHAR *retval = string;
1306 int ch = 0;
1307
1308 if (count <= 0)
1309 return(NULL);
1310
1311 while (--count)
1312 {
1313 if(!ReadFile(stream, &ch, 1, &read_bytes, NULL) ||
1314 !read_bytes)
1315 {
1316 if (pointer == string) {
1317 retval=NULL;
1318 goto done;
1319 }
1320 break;
1321 }
1322
1323 if ((*pointer++ = (CHAR)ch) == '\n') {
1324 break;
1325 }
1326 }
1327
1328 *pointer = '\0';
1329
1330 /* Common return */
1331 done:
1332 return(retval);
1333 } // end _fgets()
1334
1335 BOOLEAN
1336 ata_bblk(
1337 int bus_id,
1338 int dev_id,
1339 int list_bb
1340 )
1341 {
1342 char dev_name[64];
1343 char tmp[64];
1344 char DevSerial[128];
1345 HANDLE h = NULL;
1346 HANDLE hf = NULL;
1347 ULONG status;
1348 ULONG returned;
1349 SCSI_ADDRESS addr;
1350 ULONG len;
1351 ULONG Length;
1352 BOOLEAN retval = FALSE;
1353 HKEY hKey2 = NULL;
1354 char* bblist = NULL;
1355 LONGLONG tmp_bb_lba;
1356 LONGLONG tmp_bb_len;
1357 char BB_Msg[256];
1358 int radix=gRadix;
1359 int i, j;
1360 ULONG b;
1361
1362 if(dev_id == -1) {
1363 printf("\nERROR: Target device/bus ID must be specified\n\n");
1364 print_help();
1365 return FALSE;
1366 }
1367 if(((dev_id >> 16) & 0xff) == 0xff) {
1368 printf("\nERROR: Target device bus number (channel) must be specified with b:<bus id>\n\n");
1369 print_help();
1370 return FALSE;
1371 }
1372 if(((dev_id >> 8) & 0xff) == 0xff) {
1373 printf("\nERROR: Target device ID must be specified with d:<device id>\n\n");
1374 print_help();
1375 return FALSE;
1376 }
1377 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1378 h = ata_open_dev(dev_name);
1379 if(!h) {
1380 if(bus_id == -1) {
1381 printf("Controller number must be specified\n");
1382 } else {
1383 printf("Can't open Controller %d\n", bus_id);
1384 }
1385 return FALSE;
1386 }
1387
1388 if(list_bb == 0) {
1389 hf = ata_open_file(g_bb_list, FALSE);
1390 if(!hf) {
1391 printf("Can't open bad block list file:\n %s\n", g_bb_list);
1392 ata_close_dev(h);
1393 return FALSE;
1394 }
1395
1396 len = GetFileSize(hf, NULL);
1397 if(!len || len == INVALID_FILE_SIZE)
1398 goto exit;
1399 bblist = (char*)GlobalAlloc(GMEM_FIXED, len*8);
1400 }
1401
1402 if(!ata_check_unit(h, dev_id | (bus_id << 24))) {
1403 goto exit;
1404 }
1405
1406 hKey2 = ata_get_bblist_regh(&g_ident, DevSerial, list_bb==1);
1407 if(!hKey2) {
1408 printf("Can't open registry key:\n HKLM\\SYSTEM\\CurrentControlSet\\Services\\UniATA\\Parameters\\BadBlocks\n");
1409 goto exit;
1410 }
1411
1412 if(list_bb == -1) {
1413 if(RegDeleteValue(hKey2, DevSerial) != ERROR_SUCCESS) {
1414 printf("Can't delete registry value:\n %s\n", DevSerial);
1415 goto exit;
1416 }
1417
1418 addr.PortNumber = bus_id;
1419 addr.PathId = (UCHAR)(dev_id >> 16);
1420 addr.TargetId = (UCHAR)(dev_id >> 8);
1421 addr.Lun = (UCHAR)(dev_id);
1422
1423 status = ata_send_ioctl(h, &addr, (PCHAR)"-UNIATA-",
1424 IOCTL_SCSI_MINIPORT_UNIATA_RESETBB,
1425 NULL, 0,
1426 NULL, 0,
1427 &returned);
1428 if(!status) {
1429 printf("Bad block list shall be cleared after reboot.\n");
1430 } else {
1431 printf("Bad block list cleared\n");
1432 }
1433 } else
1434 if(list_bb == 0) {
1435 LONGLONG* pData = ((LONGLONG*)bblist);
1436 char a;
1437 int k, k0;
1438 Length=0;
1439 i=0;
1440 j=0;
1441 k=0;
1442 while(_fgets(BB_Msg, sizeof(BB_Msg), hf)) {
1443 j++;
1444 BB_Msg[sizeof(BB_Msg)-1] = 0;
1445 k=0;
1446 while((a = BB_Msg[k])) {
1447 if(a == ' ' || a == '\t' || a == '\r') {
1448 k++;
1449 continue;
1450 }
1451 break;
1452 }
1453 if(!a || a == ';' || a == '#') {
1454 continue;
1455 }
1456 if(!strncmp(BB_Msg+k, "hex:", 4)) {
1457 radix=16;
1458 continue;
1459 }
1460 if(!strncmp(BB_Msg+k, "dec:", 4)) {
1461 radix=10;
1462 continue;
1463 }
1464 k0 = k;
1465 while((a = BB_Msg[k])) {
1466 if(a == ' ' || a == '\t' || a == '\r') {
1467 BB_Msg[k] = '\t';
1468 }
1469 k++;
1470 if(a == ';' || a == '#') {
1471 break;
1472 }
1473 if(a >= '0' && a <= '9') {
1474 continue;
1475 }
1476 if(radix == 16 && ((a >= 'A' && a <= 'F') || (a >= 'a' && a <= 'f'))) {
1477 continue;
1478 }
1479 printf("Bad input BB list file:\n %s\n", g_bb_list);
1480 printf("Illegal character '%1.1s' in line %d:\n%s\n", BB_Msg+k-1, j, BB_Msg);
1481 k0=-1;
1482 break;
1483 }
1484 if(k0 == -1) {
1485 continue;
1486 }
1487 k = k0;
1488 if(radix == 10) {
1489 b = sscanf(BB_Msg+k, "%I64u\t%I64u", &tmp_bb_lba, &tmp_bb_len);
1490 } else {
1491 b = sscanf(BB_Msg+k, "%I64x\t%I64x", &tmp_bb_lba, &tmp_bb_len);
1492 }
1493 if(b == 1) {
1494 tmp_bb_len = 1;
1495 } else
1496 if(b != 2) {
1497 printf("Bad input BB list file:\n %s\n", g_bb_list);
1498 printf("Can't parse line %d:\n%s\n", j, BB_Msg);
1499 continue;
1500 }
1501 if(!tmp_bb_len) {
1502 printf("Bad input BB list file:\n %s\n", g_bb_list);
1503 printf("BlockCount evaluated to 0 in line %d:\n%s\n", j, BB_Msg);
1504 continue;
1505 }
1506 if(tmp_bb_lba < 0) {
1507 printf("Bad input BB list file:\n %s\n", g_bb_list);
1508 printf("Start LBA evaluated to negative in line %d:\n%s\n", j, BB_Msg);
1509 continue;
1510 }
1511 if(tmp_bb_len < 0) {
1512 printf("Bad input BB list file:\n %s\n", g_bb_list);
1513 printf("BlockCount evaluated to negative in line %d:\n%s\n", j, BB_Msg);
1514 continue;
1515 }
1516
1517 if(i &&
1518 (pData[(i-1)*2+1] == tmp_bb_lba)) {
1519 pData[(i-1)*2+1]+=tmp_bb_len;
1520 } else {
1521 pData[i*2+0]=tmp_bb_lba;
1522 pData[i*2+1]=tmp_bb_lba+tmp_bb_len;
1523 i++;
1524 Length += sizeof(LONGLONG)*2;
1525 }
1526 }
1527
1528 if(RegSetValueEx(hKey2, DevSerial, NULL, REG_BINARY, (const UCHAR*)bblist, Length) != ERROR_SUCCESS) {
1529 printf("Can't set registry value:\n %s\n", DevSerial);
1530 goto exit;
1531 }
1532 /*
1533 addr.PortNumber = bus_id;
1534 addr.PathId = (UCHAR)(dev_id >> 16);
1535 addr.TargetId = (UCHAR)(dev_id >> 8);
1536 addr.Lun = (UCHAR)(dev_id);
1537
1538 status = ata_send_ioctl(h, &addr, "-UNIATA-",
1539 IOCTL_SCSI_MINIPORT_UNIATA_SETBB,
1540 NULL, 0,
1541 NULL, 0,
1542 &returned);
1543 */
1544 printf("Bad block list shall be applied after reboot\n");
1545 } else {
1546 len = 0;
1547 returned = RegQueryValueEx(hKey2, DevSerial, NULL, NULL, NULL, &len);
1548 if(returned == 2) {
1549 printf("No bad block list assigned\n");
1550 goto exit;
1551 } else
1552 if(returned != ERROR_SUCCESS) {
1553 printf("Can't get registry value:\n %s\n", DevSerial);
1554 goto exit;
1555 }
1556
1557 hf = ata_open_file(g_bb_list, TRUE);
1558 if(!hf) {
1559 printf("Can't create bad block list file:\n %s\n", g_bb_list);
1560 goto exit;
1561 }
1562
1563 bblist = (char*)GlobalAlloc(GMEM_FIXED, len);
1564 if(RegQueryValueEx(hKey2, DevSerial, NULL, NULL, (UCHAR*)bblist, &len) != ERROR_SUCCESS) {
1565 printf("Can't get registry value:\n %s\n", DevSerial);
1566 goto exit;
1567 }
1568 if(g_bb_list) {
1569 for (j = 0; j < 20; j += 2) {
1570 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.ModelNumber))[j]);
1571 }
1572 b = sprintf(BB_Msg, "#model: %20.20s\n", tmp);
1573 WriteFile(hf, BB_Msg, b, &returned, NULL);
1574 for (j = 0; j < 4; j += 2) {
1575 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.FirmwareRevision))[j]);
1576 }
1577 b = sprintf(BB_Msg, "#rev: %4.4s\n", tmp);
1578 WriteFile(hf, BB_Msg, b, &returned, NULL);
1579 for (j = 0; j < 20; j += 2) {
1580 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.SerialNumber))[j]);
1581 }
1582 b = sprintf(BB_Msg, "#s/n: %20.20s\n", tmp);
1583 WriteFile(hf, BB_Msg, b, &returned, NULL);
1584 b = sprintf(BB_Msg, "#%s\n", DevSerial);
1585 WriteFile(hf, BB_Msg, b, &returned, NULL);
1586 b = sprintf(BB_Msg, "#Starting LBA\tNum. of Blocks\n");
1587 WriteFile(hf, BB_Msg, b, &returned, NULL);
1588 b = sprintf(BB_Msg, "hex:\n");
1589 WriteFile(hf, BB_Msg, b, &returned, NULL);
1590 } else {
1591 b = sprintf(BB_Msg, "Starting LBA\tNum. of Blocks (HEX)\n");
1592 WriteFile(hf, BB_Msg, b, &returned, NULL);
1593 }
1594 i = 0;
1595 while(len >= sizeof(LONGLONG)*2) {
1596 tmp_bb_lba = ((LONGLONG*)bblist)[i*2+0];
1597 tmp_bb_len = ((LONGLONG*)bblist)[i*2+1] - tmp_bb_lba;
1598 b = sprintf(BB_Msg, "%I64u\t%I64u\n", tmp_bb_lba, tmp_bb_len);
1599 WriteFile(hf, BB_Msg, b, &returned, NULL);
1600 i++;
1601 len -= sizeof(LONGLONG)*2;
1602 }
1603 }
1604 retval = TRUE;
1605 exit:
1606 if(hKey2)
1607 RegCloseKey(hKey2);
1608 if(bblist) {
1609 GlobalFree(bblist);
1610 }
1611 ata_close_dev(hf);
1612 ata_close_dev(h);
1613 return retval;
1614 } // end ata_bblk()
1615
1616 BOOLEAN
1617 ata_power_mode(
1618 int bus_id,
1619 int dev_id,
1620 int power_mode
1621 )
1622 {
1623 char dev_name[64];
1624 HANDLE h;
1625 ULONG status;
1626 ULONG returned;
1627 SCSI_ADDRESS addr;
1628 CDB cdb;
1629 SENSE_DATA senseData;
1630
1631 if(dev_id == -1) {
1632 return FALSE;
1633 }
1634 if(!power_mode) {
1635 return TRUE;
1636 }
1637
1638 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1639 h = ata_open_dev(dev_name);
1640 if(!h)
1641 return FALSE;
1642 addr.PortNumber = bus_id;
1643 addr.PathId = (UCHAR)(dev_id >> 16);
1644 addr.TargetId = (UCHAR)(dev_id >> 8);
1645 addr.Lun = (UCHAR)(dev_id);
1646
1647 memset(&cdb, 0, sizeof(cdb));
1648 cdb.START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
1649 cdb.START_STOP.Immediate = 1;
1650 cdb.START_STOP.PowerConditions = power_mode;
1651 cdb.START_STOP.Start = (power_mode != StartStop_Power_Sleep);
1652
1653 printf("Changing power state to ...\n");
1654
1655 status = ata_send_scsi(h, &addr, &cdb, 6,
1656 NULL, 0, FALSE,
1657 &senseData, &returned);
1658 ata_close_dev(h);
1659 return TRUE;
1660 } // end ata_power_mode()
1661
1662 int
1663 ata_num_to_x_dev(
1664 char a
1665 )
1666 {
1667 if(a >= '0' && a <= '9')
1668 return a-'0';
1669 return -1;
1670 }
1671
1672 int
1673 main (
1674 int argc,
1675 char* argv[]
1676 )
1677 {
1678 //ULONG Flags = 0;
1679 int i, j;
1680 char a;
1681 int bus_id = -1;
1682 int dev_id = -1;
1683 int cmd = 0;
1684 int lock = -1;
1685 int b_dev=-1, d_dev=-1, l_dev=0;
1686 int mode=-1;
1687 int list_bb=0;
1688 int persistent_hide=0;
1689 int power_mode=StartStop_Power_NoChg;
1690
1691 printf("Console ATA control utility for Windows NT3.51/NT4/2000/XP/2003\n"
1692 "Version 0." UNIATA_VER_STR ", Copyright (c) Alexander A. Telyatnikov, 2003-2012\n"
1693 "Home site: http://alter.org.ua\n");
1694
1695 for(i=1; i<argc; i++) {
1696 if(!argv[i])
1697 continue;
1698 if((a = argv[i][0]) != '-') {
1699 for(j=0; (a = argv[i][j]); j++) {
1700 switch(a) {
1701 case 'a' :
1702 case 's' :
1703 case 'c' :
1704 j++;
1705 bus_id = ata_num_to_x_dev(argv[i][j]);
1706 break;
1707 case 'b' :
1708 j++;
1709 b_dev = ata_num_to_x_dev(argv[i][j]);
1710 break;
1711 case 'd' :
1712 j++;
1713 d_dev = ata_num_to_x_dev(argv[i][j]);
1714 break;
1715 case 'l' :
1716 j++;
1717 l_dev = ata_num_to_x_dev(argv[i][j]);
1718 break;
1719 case ':' :
1720 break;
1721 default:
1722 print_help();
1723 }
1724 }
1725 continue;
1726 }
1727 j=1;
1728 while(argv[i] && (a = argv[i][j]) && (a != ' ') && (a != '\t')) {
1729 switch(a) {
1730 case 'l' :
1731 if(cmd || lock>0) {
1732 print_help();
1733 }
1734 cmd = CMD_ATA_LIST;
1735 break;
1736 case 'x' :
1737 g_extended = 1;
1738 break;
1739 case 'a' :
1740 g_adapter_info = 1;
1741 break;
1742 case 'S' :
1743 persistent_hide = 1;
1744 case 's' :
1745 if(cmd || lock>0) {
1746 print_help();
1747 }
1748 cmd = CMD_ATA_FIND;
1749 d_dev = 0;
1750 break;
1751 case 'H' :
1752 persistent_hide = 1;
1753 case 'h' :
1754 if(cmd) {
1755 print_help();
1756 }
1757 cmd = CMD_ATA_HIDE;
1758 d_dev = 0;
1759 break;
1760 case 'm' :
1761 if(cmd) {
1762 print_help();
1763 }
1764 cmd = CMD_ATA_MODE;
1765 i++;
1766 if(!argv[i]) {
1767 print_help();
1768 }
1769 mode = ata_str_to_mode(argv[i]);
1770 if(mode == -1) {
1771 i--;
1772 } else {
1773 j = strlen(argv[i])-1;
1774 }
1775 break;
1776 case 'r' :
1777 if(cmd) {
1778 print_help();
1779 }
1780 cmd = CMD_ATA_RESET;
1781 break;
1782 case 'b' :
1783 if(cmd) {
1784 print_help();
1785 }
1786 switch(argv[i][j+1]) {
1787 case 'l':
1788 list_bb = 1;
1789 break;
1790 case 'a':
1791 list_bb = 0;
1792 break;
1793 case 'r':
1794 list_bb = -1;
1795 break;
1796 default:
1797 j--;
1798 }
1799 j++;
1800 cmd = CMD_ATA_BBLK;
1801 break;
1802 case 'f' :
1803 if(cmd != CMD_ATA_BBLK) {
1804 print_help();
1805 }
1806 i++;
1807 if(!argv[i]) {
1808 print_help();
1809 }
1810 g_bb_list=argv[i];
1811 j = strlen(argv[i])-1;
1812 break;
1813 case 'p' :
1814 if(cmd && (cmd != CMD_ATA_FIND) && (cmd != CMD_ATA_HIDE)) {
1815 print_help();
1816 }
1817 switch(argv[i][j+1]) {
1818 case '0':
1819 case 'a':
1820 // do nothing
1821 break;
1822 case '1':
1823 case 'i':
1824 power_mode = StartStop_Power_Idle;
1825 break;
1826 case '2':
1827 case 's':
1828 power_mode = StartStop_Power_Standby;
1829 break;
1830 case '3':
1831 case 'p':
1832 power_mode = StartStop_Power_Sleep;
1833 break;
1834 default:
1835 j--;
1836 }
1837 j++;
1838 if(power_mode && !cmd) {
1839 cmd = CMD_ATA_POWER;
1840 }
1841 break;
1842 case 'D' :
1843 power_mode = StartStop_Power_Sleep;
1844 if(cmd && (cmd != CMD_ATA_HIDE)) {
1845 print_help();
1846 }
1847 case 'd' :
1848 if(cmd && (cmd != CMD_ATA_FIND) && (cmd != CMD_ATA_HIDE) && (cmd != CMD_ATA_POWER)) {
1849 print_help();
1850 }
1851 if(!cmd) {
1852 cmd = CMD_ATA_HIDE;
1853 }
1854 i++;
1855 if(!argv[i]) {
1856 print_help();
1857 }
1858 if(!sscanf(argv[i], "%d", &lock)) {
1859 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
1860 i--;
1861 }
1862 j = strlen(argv[i])-1;
1863 break;
1864 case 'n' :
1865 if(cmd != CMD_ATA_BBLK) {
1866 print_help();
1867 }
1868 i++;
1869 if(!argv[i]) {
1870 print_help();
1871 }
1872 if(!strcmp(argv[i], "hex") ||
1873 !strcmp(argv[i], "16")) {
1874 gRadix = 16;
1875 } else
1876 if(!strcmp(argv[i], "dec") ||
1877 !strcmp(argv[i], "10")) {
1878 gRadix = 10;
1879 } else {
1880 print_help();
1881 }
1882 j = strlen(argv[i])-1;
1883 break;
1884 case '?' :
1885 default:
1886 print_help();
1887 }
1888 j++;
1889 }
1890 }
1891
1892 if(g_adapter_info && !cmd) {
1893 cmd = CMD_ATA_LIST;
1894 b_dev = 127;
1895 d_dev = 127;
1896 l_dev = 127;
1897 } else
1898 if((d_dev == -1) && (b_dev != -1)) {
1899 d_dev = 127;
1900 l_dev = 127;
1901 }
1902
1903 if((d_dev != -1) && (b_dev != -1)) {
1904 dev_id = (b_dev << 16) | (d_dev << 8) | l_dev;
1905 }
1906 if(cmd == CMD_ATA_LIST) {
1907 ata_list(bus_id, dev_id);
1908 } else
1909 if(cmd == CMD_ATA_MODE) {
1910 ata_mode(bus_id, dev_id, mode);
1911 } else
1912 if(cmd == CMD_ATA_RESET) {
1913 ata_reset(bus_id, dev_id);
1914 } else
1915 if(cmd == CMD_ATA_FIND) {
1916 ata_scan(bus_id, dev_id, lock, persistent_hide);
1917 } else
1918 if(cmd == CMD_ATA_HIDE) {
1919 ata_hide(bus_id, dev_id, lock, persistent_hide, power_mode);
1920 } else
1921 if(cmd == CMD_ATA_BBLK) {
1922 ata_bblk(bus_id, dev_id, list_bb);
1923 } else
1924 if(cmd == CMD_ATA_POWER) {
1925 ata_power_mode(bus_id, dev_id, power_mode);
1926 } else {
1927 print_help();
1928 }
1929 exit(0);
1930 }
1931