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