Create a branch for Aleksandar Andrejevic for his work on NTVDM. See http://jira...
[reactos.git] / 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 if(!status) {
1234 printf("Delete failed\n");
1235 } else {
1236 printf("Device is detached\n");
1237 }
1238 ata_close_dev(h);
1239 return status ? TRUE : FALSE;
1240 } // end ata_hide()
1241
1242 BOOLEAN
1243 ata_scan(
1244 int bus_id,
1245 int dev_id,
1246 int lock,
1247 int unhide
1248 )
1249 {
1250 char dev_name[64];
1251 HANDLE h;
1252 ULONG status;
1253 ULONG returned;
1254 SCSI_ADDRESS addr;
1255 ADDREMOVEDEV to;
1256
1257 if(dev_id == -1) {
1258 return FALSE;
1259 }
1260 if(lock < 0) {
1261 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
1262 }
1263 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1264 h = ata_open_dev(dev_name);
1265 if(!h)
1266 return FALSE;
1267
1268 if((UCHAR)(dev_id) != 0xff &&
1269 (UCHAR)(dev_id >> 8) != 0xff) {
1270
1271 addr.PortNumber = bus_id;
1272 addr.PathId = (UCHAR)(dev_id >> 16);
1273 addr.TargetId = 0;
1274 addr.Lun = 0;
1275
1276 to.WaitForPhysicalLink = lock;
1277 to.Flags = unhide ? UNIATA_ADD_FLAGS_UNHIDE : 0;
1278
1279 printf("Scaning bus for new devices.\n");
1280 if(lock) {
1281 printf("You have %d seconds to connect device.\n", lock);
1282 }
1283 status = ata_send_ioctl(h, &addr, (PCHAR)"-UNIATA-",
1284 IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES,
1285 &to, sizeof(to),
1286 NULL, 0,
1287 &returned);
1288 } else {
1289 status = DeviceIoControl(h,
1290 IOCTL_SCSI_RESCAN_BUS,
1291 NULL, 0,
1292 NULL, 0,
1293 &returned,
1294 FALSE);
1295 }
1296 ata_close_dev(h);
1297 return status ? TRUE : FALSE;
1298 } // end ata_scan()
1299
1300 CHAR*
1301 _fgets(
1302 CHAR *string,
1303 int count,
1304 HANDLE stream
1305 )
1306 {
1307 CHAR *pointer = string;
1308 ULONG read_bytes;
1309
1310 CHAR *retval = string;
1311 int ch = 0;
1312
1313 if (count <= 0)
1314 return(NULL);
1315
1316 while (--count)
1317 {
1318 if(!ReadFile(stream, &ch, 1, &read_bytes, NULL) ||
1319 !read_bytes)
1320 {
1321 if (pointer == string) {
1322 retval=NULL;
1323 goto done;
1324 }
1325 break;
1326 }
1327
1328 if ((*pointer++ = (CHAR)ch) == '\n') {
1329 break;
1330 }
1331 }
1332
1333 *pointer = '\0';
1334
1335 /* Common return */
1336 done:
1337 return(retval);
1338 } // end _fgets()
1339
1340 BOOLEAN
1341 ata_bblk(
1342 int bus_id,
1343 int dev_id,
1344 int list_bb
1345 )
1346 {
1347 char dev_name[64];
1348 char tmp[64];
1349 char DevSerial[128];
1350 HANDLE h = NULL;
1351 HANDLE hf = NULL;
1352 ULONG status;
1353 ULONG returned;
1354 SCSI_ADDRESS addr;
1355 ULONG len;
1356 ULONG Length;
1357 BOOLEAN retval = FALSE;
1358 HKEY hKey2 = NULL;
1359 char* bblist = NULL;
1360 LONGLONG tmp_bb_lba;
1361 LONGLONG tmp_bb_len;
1362 char BB_Msg[256];
1363 int radix=gRadix;
1364 int i, j;
1365 ULONG b;
1366
1367 if(dev_id == -1) {
1368 printf("\nERROR: Target device/bus ID must be specified\n\n");
1369 print_help();
1370 return FALSE;
1371 }
1372 if(((dev_id >> 16) & 0xff) == 0xff) {
1373 printf("\nERROR: Target device bus number (channel) must be specified with b:<bus id>\n\n");
1374 print_help();
1375 return FALSE;
1376 }
1377 if(((dev_id >> 8) & 0xff) == 0xff) {
1378 printf("\nERROR: Target device ID must be specified with d:<device id>\n\n");
1379 print_help();
1380 return FALSE;
1381 }
1382 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1383 h = ata_open_dev(dev_name);
1384 if(!h) {
1385 if(bus_id == -1) {
1386 printf("Controller number must be specified\n");
1387 } else {
1388 printf("Can't open Controller %d\n", bus_id);
1389 }
1390 return FALSE;
1391 }
1392
1393 if(list_bb == 0) {
1394 hf = ata_open_file(g_bb_list, FALSE);
1395 if(!hf) {
1396 printf("Can't open bad block list file:\n %s\n", g_bb_list);
1397 ata_close_dev(h);
1398 return FALSE;
1399 }
1400
1401 len = GetFileSize(hf, NULL);
1402 if(!len || len == INVALID_FILE_SIZE)
1403 goto exit;
1404 bblist = (char*)GlobalAlloc(GMEM_FIXED, len*8);
1405 }
1406
1407 if(!ata_check_unit(h, dev_id | (bus_id << 24))) {
1408 goto exit;
1409 }
1410
1411 hKey2 = ata_get_bblist_regh(&g_ident, DevSerial, list_bb==1);
1412 if(!hKey2) {
1413 printf("Can't open registry key:\n HKLM\\SYSTEM\\CurrentControlSet\\Services\\UniATA\\Parameters\\BadBlocks\n");
1414 goto exit;
1415 }
1416
1417 if(list_bb == -1) {
1418 if(RegDeleteValue(hKey2, DevSerial) != ERROR_SUCCESS) {
1419 printf("Can't delete registry value:\n %s\n", DevSerial);
1420 goto exit;
1421 }
1422
1423 addr.PortNumber = bus_id;
1424 addr.PathId = (UCHAR)(dev_id >> 16);
1425 addr.TargetId = (UCHAR)(dev_id >> 8);
1426 addr.Lun = (UCHAR)(dev_id);
1427
1428 status = ata_send_ioctl(h, &addr, (PCHAR)"-UNIATA-",
1429 IOCTL_SCSI_MINIPORT_UNIATA_RESETBB,
1430 NULL, 0,
1431 NULL, 0,
1432 &returned);
1433 if(!status) {
1434 printf("Bad block list shall be cleared after reboot.\n");
1435 } else {
1436 printf("Bad block list cleared\n");
1437 }
1438 } else
1439 if(list_bb == 0) {
1440 LONGLONG* pData = ((LONGLONG*)bblist);
1441 char a;
1442 int k, k0;
1443 Length=0;
1444 i=0;
1445 j=0;
1446 k=0;
1447 while(_fgets(BB_Msg, sizeof(BB_Msg), hf)) {
1448 j++;
1449 BB_Msg[sizeof(BB_Msg)-1] = 0;
1450 k=0;
1451 while((a = BB_Msg[k])) {
1452 if(a == ' ' || a == '\t' || a == '\r') {
1453 k++;
1454 continue;
1455 }
1456 break;
1457 }
1458 if(!a || a == ';' || a == '#') {
1459 continue;
1460 }
1461 if(!strncmp(BB_Msg+k, "hex:", 4)) {
1462 radix=16;
1463 continue;
1464 }
1465 if(!strncmp(BB_Msg+k, "dec:", 4)) {
1466 radix=10;
1467 continue;
1468 }
1469 k0 = k;
1470 while((a = BB_Msg[k])) {
1471 if(a == ' ' || a == '\t' || a == '\r') {
1472 BB_Msg[k] = '\t';
1473 }
1474 k++;
1475 if(a == ';' || a == '#') {
1476 break;
1477 }
1478 if(a >= '0' && a <= '9') {
1479 continue;
1480 }
1481 if(radix == 16 && ((a >= 'A' && a <= 'F') || (a >= 'a' && a <= 'f'))) {
1482 continue;
1483 }
1484 printf("Bad input BB list file:\n %s\n", g_bb_list);
1485 printf("Illegal character '%1.1s' in line %d:\n%s\n", BB_Msg+k-1, j, BB_Msg);
1486 k0=-1;
1487 break;
1488 }
1489 if(k0 == -1) {
1490 continue;
1491 }
1492 k = k0;
1493 if(radix == 10) {
1494 b = sscanf(BB_Msg+k, "%I64u\t%I64u", &tmp_bb_lba, &tmp_bb_len);
1495 } else {
1496 b = sscanf(BB_Msg+k, "%I64x\t%I64x", &tmp_bb_lba, &tmp_bb_len);
1497 }
1498 if(b == 1) {
1499 tmp_bb_len = 1;
1500 } else
1501 if(b != 2) {
1502 printf("Bad input BB list file:\n %s\n", g_bb_list);
1503 printf("Can't parse line %d:\n%s\n", j, BB_Msg);
1504 continue;
1505 }
1506 if(!tmp_bb_len) {
1507 printf("Bad input BB list file:\n %s\n", g_bb_list);
1508 printf("BlockCount evaluated to 0 in line %d:\n%s\n", j, BB_Msg);
1509 continue;
1510 }
1511 if(tmp_bb_lba < 0) {
1512 printf("Bad input BB list file:\n %s\n", g_bb_list);
1513 printf("Start LBA evaluated to negative in line %d:\n%s\n", j, BB_Msg);
1514 continue;
1515 }
1516 if(tmp_bb_len < 0) {
1517 printf("Bad input BB list file:\n %s\n", g_bb_list);
1518 printf("BlockCount evaluated to negative in line %d:\n%s\n", j, BB_Msg);
1519 continue;
1520 }
1521
1522 if(i &&
1523 (pData[(i-1)*2+1] == tmp_bb_lba)) {
1524 pData[(i-1)*2+1]+=tmp_bb_len;
1525 } else {
1526 pData[i*2+0]=tmp_bb_lba;
1527 pData[i*2+1]=tmp_bb_lba+tmp_bb_len;
1528 i++;
1529 Length += sizeof(LONGLONG)*2;
1530 }
1531 }
1532
1533 if(RegSetValueEx(hKey2, DevSerial, NULL, REG_BINARY, (const UCHAR*)bblist, Length) != ERROR_SUCCESS) {
1534 printf("Can't set registry value:\n %s\n", DevSerial);
1535 goto exit;
1536 }
1537 /*
1538 addr.PortNumber = bus_id;
1539 addr.PathId = (UCHAR)(dev_id >> 16);
1540 addr.TargetId = (UCHAR)(dev_id >> 8);
1541 addr.Lun = (UCHAR)(dev_id);
1542
1543 status = ata_send_ioctl(h, &addr, "-UNIATA-",
1544 IOCTL_SCSI_MINIPORT_UNIATA_SETBB,
1545 NULL, 0,
1546 NULL, 0,
1547 &returned);
1548 */
1549 printf("Bad block list shall be applied after reboot\n");
1550 } else {
1551 len = 0;
1552 returned = RegQueryValueEx(hKey2, DevSerial, NULL, NULL, NULL, &len);
1553 if(returned == 2) {
1554 printf("No bad block list assigned\n");
1555 goto exit;
1556 } else
1557 if(returned != ERROR_SUCCESS) {
1558 printf("Can't get registry value:\n %s\n", DevSerial);
1559 goto exit;
1560 }
1561
1562 hf = ata_open_file(g_bb_list, TRUE);
1563 if(!hf) {
1564 printf("Can't create bad block list file:\n %s\n", g_bb_list);
1565 goto exit;
1566 }
1567
1568 bblist = (char*)GlobalAlloc(GMEM_FIXED, len);
1569 if(RegQueryValueEx(hKey2, DevSerial, NULL, NULL, (UCHAR*)bblist, &len) != ERROR_SUCCESS) {
1570 printf("Can't get registry value:\n %s\n", DevSerial);
1571 goto exit;
1572 }
1573 if(g_bb_list) {
1574 for (j = 0; j < 20; j += 2) {
1575 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.ModelNumber))[j]);
1576 }
1577 b = sprintf(BB_Msg, "#model: %20.20s\n", tmp);
1578 WriteFile(hf, BB_Msg, b, &returned, NULL);
1579 for (j = 0; j < 4; j += 2) {
1580 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.FirmwareRevision))[j]);
1581 }
1582 b = sprintf(BB_Msg, "#rev: %4.4s\n", tmp);
1583 WriteFile(hf, BB_Msg, b, &returned, NULL);
1584 for (j = 0; j < 20; j += 2) {
1585 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.SerialNumber))[j]);
1586 }
1587 b = sprintf(BB_Msg, "#s/n: %20.20s\n", tmp);
1588 WriteFile(hf, BB_Msg, b, &returned, NULL);
1589 b = sprintf(BB_Msg, "#%s\n", DevSerial);
1590 WriteFile(hf, BB_Msg, b, &returned, NULL);
1591 b = sprintf(BB_Msg, "#Starting LBA\tNum. of Blocks\n");
1592 WriteFile(hf, BB_Msg, b, &returned, NULL);
1593 b = sprintf(BB_Msg, "hex:\n");
1594 WriteFile(hf, BB_Msg, b, &returned, NULL);
1595 } else {
1596 b = sprintf(BB_Msg, "Starting LBA\tNum. of Blocks (HEX)\n");
1597 WriteFile(hf, BB_Msg, b, &returned, NULL);
1598 }
1599 i = 0;
1600 while(len >= sizeof(LONGLONG)*2) {
1601 tmp_bb_lba = ((LONGLONG*)bblist)[i*2+0];
1602 tmp_bb_len = ((LONGLONG*)bblist)[i*2+1] - tmp_bb_lba;
1603 b = sprintf(BB_Msg, "%I64u\t%I64u\n", tmp_bb_lba, tmp_bb_len);
1604 WriteFile(hf, BB_Msg, b, &returned, NULL);
1605 i++;
1606 len -= sizeof(LONGLONG)*2;
1607 }
1608 }
1609 retval = TRUE;
1610 exit:
1611 if(hKey2)
1612 RegCloseKey(hKey2);
1613 if(bblist) {
1614 GlobalFree(bblist);
1615 }
1616 ata_close_dev(hf);
1617 ata_close_dev(h);
1618 return retval;
1619 } // end ata_bblk()
1620
1621 BOOLEAN
1622 ata_power_mode(
1623 int bus_id,
1624 int dev_id,
1625 int power_mode
1626 )
1627 {
1628 char dev_name[64];
1629 HANDLE h;
1630 ULONG status;
1631 ULONG returned;
1632 SCSI_ADDRESS addr;
1633 CDB cdb;
1634 SENSE_DATA senseData;
1635
1636 if(dev_id == -1) {
1637 return FALSE;
1638 }
1639 if(!power_mode) {
1640 return TRUE;
1641 }
1642
1643 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1644 h = ata_open_dev(dev_name);
1645 if(!h)
1646 return FALSE;
1647 addr.PortNumber = bus_id;
1648 addr.PathId = (UCHAR)(dev_id >> 16);
1649 addr.TargetId = (UCHAR)(dev_id >> 8);
1650 addr.Lun = (UCHAR)(dev_id);
1651
1652 memset(&cdb, 0, sizeof(cdb));
1653 cdb.START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
1654 cdb.START_STOP.Immediate = 1;
1655 cdb.START_STOP.PowerConditions = power_mode;
1656 cdb.START_STOP.Start = (power_mode != StartStop_Power_Sleep);
1657
1658 printf("Changing power state to ...\n");
1659
1660 status = ata_send_scsi(h, &addr, &cdb, 6,
1661 NULL, 0, FALSE,
1662 &senseData, &returned);
1663 ata_close_dev(h);
1664 return status ? TRUE : FALSE;
1665 } // end ata_power_mode()
1666
1667 int
1668 ata_num_to_x_dev(
1669 char a
1670 )
1671 {
1672 if(a >= '0' && a <= '9')
1673 return a-'0';
1674 return -1;
1675 }
1676
1677 int
1678 main (
1679 int argc,
1680 char* argv[]
1681 )
1682 {
1683 //ULONG Flags = 0;
1684 int i, j;
1685 char a;
1686 int bus_id = -1;
1687 int dev_id = -1;
1688 int cmd = 0;
1689 int lock = -1;
1690 int b_dev=-1, d_dev=-1, l_dev=0;
1691 int mode=-1;
1692 int list_bb=0;
1693 int persistent_hide=0;
1694 int power_mode=StartStop_Power_NoChg;
1695
1696 printf("Console ATA control utility for Windows NT3.51/NT4/2000/XP/2003\n"
1697 "Version 0." UNIATA_VER_STR ", Copyright (c) Alexander A. Telyatnikov, 2003-2012\n"
1698 "Home site: http://alter.org.ua\n");
1699
1700 for(i=1; i<argc; i++) {
1701 if(!argv[i])
1702 continue;
1703 if((a = argv[i][0]) != '-') {
1704 for(j=0; (a = argv[i][j]); j++) {
1705 switch(a) {
1706 case 'a' :
1707 case 's' :
1708 case 'c' :
1709 j++;
1710 bus_id = ata_num_to_x_dev(argv[i][j]);
1711 break;
1712 case 'b' :
1713 j++;
1714 b_dev = ata_num_to_x_dev(argv[i][j]);
1715 break;
1716 case 'd' :
1717 j++;
1718 d_dev = ata_num_to_x_dev(argv[i][j]);
1719 break;
1720 case 'l' :
1721 j++;
1722 l_dev = ata_num_to_x_dev(argv[i][j]);
1723 break;
1724 case ':' :
1725 break;
1726 default:
1727 print_help();
1728 }
1729 }
1730 continue;
1731 }
1732 j=1;
1733 while(argv[i] && (a = argv[i][j]) && (a != ' ') && (a != '\t')) {
1734 switch(a) {
1735 case 'l' :
1736 if(cmd || lock>0) {
1737 print_help();
1738 }
1739 cmd = CMD_ATA_LIST;
1740 break;
1741 case 'x' :
1742 g_extended = 1;
1743 break;
1744 case 'a' :
1745 g_adapter_info = 1;
1746 break;
1747 case 'S' :
1748 persistent_hide = 1;
1749 case 's' :
1750 if(cmd || lock>0) {
1751 print_help();
1752 }
1753 cmd = CMD_ATA_FIND;
1754 d_dev = 0;
1755 break;
1756 case 'H' :
1757 persistent_hide = 1;
1758 case 'h' :
1759 if(cmd) {
1760 print_help();
1761 }
1762 cmd = CMD_ATA_HIDE;
1763 d_dev = 0;
1764 break;
1765 case 'm' :
1766 if(cmd) {
1767 print_help();
1768 }
1769 cmd = CMD_ATA_MODE;
1770 i++;
1771 if(!argv[i]) {
1772 print_help();
1773 }
1774 mode = ata_str_to_mode(argv[i]);
1775 if(mode == -1) {
1776 i--;
1777 } else {
1778 j = strlen(argv[i])-1;
1779 }
1780 break;
1781 case 'r' :
1782 if(cmd) {
1783 print_help();
1784 }
1785 cmd = CMD_ATA_RESET;
1786 break;
1787 case 'b' :
1788 if(cmd) {
1789 print_help();
1790 }
1791 switch(argv[i][j+1]) {
1792 case 'l':
1793 list_bb = 1;
1794 break;
1795 case 'a':
1796 list_bb = 0;
1797 break;
1798 case 'r':
1799 list_bb = -1;
1800 break;
1801 default:
1802 j--;
1803 }
1804 j++;
1805 cmd = CMD_ATA_BBLK;
1806 break;
1807 case 'f' :
1808 if(cmd != CMD_ATA_BBLK) {
1809 print_help();
1810 }
1811 i++;
1812 if(!argv[i]) {
1813 print_help();
1814 }
1815 g_bb_list=argv[i];
1816 j = strlen(argv[i])-1;
1817 break;
1818 case 'p' :
1819 if(cmd && (cmd != CMD_ATA_FIND) && (cmd != CMD_ATA_HIDE)) {
1820 print_help();
1821 }
1822 switch(argv[i][j+1]) {
1823 case '0':
1824 case 'a':
1825 // do nothing
1826 break;
1827 case '1':
1828 case 'i':
1829 power_mode = StartStop_Power_Idle;
1830 break;
1831 case '2':
1832 case 's':
1833 power_mode = StartStop_Power_Standby;
1834 break;
1835 case '3':
1836 case 'p':
1837 power_mode = StartStop_Power_Sleep;
1838 break;
1839 default:
1840 j--;
1841 }
1842 j++;
1843 if(power_mode && !cmd) {
1844 cmd = CMD_ATA_POWER;
1845 }
1846 break;
1847 case 'D' :
1848 power_mode = StartStop_Power_Sleep;
1849 if(cmd && (cmd != CMD_ATA_HIDE)) {
1850 print_help();
1851 }
1852 case 'd' :
1853 if(cmd && (cmd != CMD_ATA_FIND) && (cmd != CMD_ATA_HIDE) && (cmd != CMD_ATA_POWER)) {
1854 print_help();
1855 }
1856 if(!cmd) {
1857 cmd = CMD_ATA_HIDE;
1858 }
1859 i++;
1860 if(!argv[i]) {
1861 print_help();
1862 }
1863 if(!sscanf(argv[i], "%d", &lock)) {
1864 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
1865 i--;
1866 }
1867 j = strlen(argv[i])-1;
1868 break;
1869 case 'n' :
1870 if(cmd != CMD_ATA_BBLK) {
1871 print_help();
1872 }
1873 i++;
1874 if(!argv[i]) {
1875 print_help();
1876 }
1877 if(!strcmp(argv[i], "hex") ||
1878 !strcmp(argv[i], "16")) {
1879 gRadix = 16;
1880 } else
1881 if(!strcmp(argv[i], "dec") ||
1882 !strcmp(argv[i], "10")) {
1883 gRadix = 10;
1884 } else {
1885 print_help();
1886 }
1887 j = strlen(argv[i])-1;
1888 break;
1889 case '?' :
1890 default:
1891 print_help();
1892 }
1893 j++;
1894 }
1895 }
1896
1897 if(g_adapter_info && !cmd) {
1898 cmd = CMD_ATA_LIST;
1899 b_dev = 127;
1900 d_dev = 127;
1901 l_dev = 127;
1902 } else
1903 if((d_dev == -1) && (b_dev != -1)) {
1904 d_dev = 127;
1905 l_dev = 127;
1906 }
1907
1908 if((d_dev != -1) && (b_dev != -1)) {
1909 dev_id = (b_dev << 16) | (d_dev << 8) | l_dev;
1910 }
1911 if(cmd == CMD_ATA_LIST) {
1912 ata_list(bus_id, dev_id);
1913 } else
1914 if(cmd == CMD_ATA_MODE) {
1915 ata_mode(bus_id, dev_id, mode);
1916 } else
1917 if(cmd == CMD_ATA_RESET) {
1918 ata_reset(bus_id, dev_id);
1919 } else
1920 if(cmd == CMD_ATA_FIND) {
1921 ata_scan(bus_id, dev_id, lock, persistent_hide);
1922 } else
1923 if(cmd == CMD_ATA_HIDE) {
1924 ata_hide(bus_id, dev_id, lock, persistent_hide, power_mode);
1925 } else
1926 if(cmd == CMD_ATA_BBLK) {
1927 ata_bblk(bus_id, dev_id, list_bb);
1928 } else
1929 if(cmd == CMD_ATA_POWER) {
1930 ata_power_mode(bus_id, dev_id, power_mode);
1931 } else {
1932 print_help();
1933 }
1934 exit(0);
1935 }
1936