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