1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License as 4 * published by the Free Software Foundation; either version 2 of 5 * the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 15 * MA 02111-1307 USA 16 */ 17/* 18 * Copyright (c) 2006 Douglas Gilbert. 19 * All rights reserved. 20 * 21 * Redistribution and use in source and binary forms, with or without 22 * modification, are permitted provided that the following conditions 23 * are met: 24 * 1. Redistributions of source code must retain the above copyright 25 * notice, this list of conditions and the following disclaimer. 26 * 2. Redistributions in binary form must reproduce the above copyright 27 * notice, this list of conditions and the following disclaimer in the 28 * documentation and/or other materials provided with the distribution. 29 * 3. The name of the author may not be used to endorse or promote products 30 * derived from this software without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 */ 45 46/* 47 * This file shows the relationship between various SCSI device naming 48 * schemes in Windows OSes (Windows 200, 2003 and XP) as seen by 49 * The SCSI Pass Through (SPT) interface. N.B. ASPI32 is not used. 50 */ 51 52#include <stdio.h> 53#include <stdlib.h> 54#include <stddef.h> 55#include <string.h> 56#include <errno.h> 57#include <ctype.h> 58#include <getopt.h> 59 60#include "sg_lib.h" 61#include "sg_pt_win32.h" 62 63#define MAX_SCSI_ELEMS 1024 64#define MAX_ADAPTER_NUM 64 65#define MAX_PHYSICALDRIVE_NUM 512 66#define MAX_CDROM_NUM 512 67#define MAX_TAPE_NUM 512 68#define MAX_HOLE_COUNT 8 69#define SCSI2_INQ_RESP_LEN 36 70#define DEF_TIMEOUT 20 71#define INQUIRY_CMD 0x12 72#define INQUIRY_CMDLEN 6 73 74struct w_scsi_elem { 75 char in_use; 76 char scsi_adapter_valid; 77 UCHAR port_num; /* <n> in '\\.\SCSI<n>:' adapter name */ 78 UCHAR bus; /* also known as pathId */ 79 UCHAR target; 80 UCHAR lun; 81 UCHAR device_claimed; /* class driver claimed this lu */ 82 UCHAR dubious_scsi; /* set if inq_resp[4] is zero */ 83 char pdt; /* peripheral device type (see SPC-4) */ 84 char volume_valid; 85 char volume_multiple; /* multiple partitions mapping to volumes */ 86 UCHAR volume_letter; /* lowest 'C:' through to 'Z:' */ 87 char physicaldrive_valid; 88 char cdrom_valid; 89 char tape_valid; 90 int physicaldrive_num; 91 int cdrom_num; 92 int tape_num; 93 unsigned char inq_resp[SCSI2_INQ_RESP_LEN]; 94}; 95 96static struct w_scsi_elem w_scsi_arr[MAX_SCSI_ELEMS]; 97 98static int next_unused_scsi_elem = 0; 99static int next_elem_after_scsi_adapter_valid = 0; 100 101 102static char * get_err_str(DWORD err, int max_b_len, char * b) 103{ 104 LPVOID lpMsgBuf; 105 int k, num, ch; 106 107 if (max_b_len < 2) { 108 if (1 == max_b_len) 109 b[0] = '\0'; 110 return b; 111 } 112 memset(b, 0, max_b_len); 113 FormatMessage( 114 FORMAT_MESSAGE_ALLOCATE_BUFFER | 115 FORMAT_MESSAGE_FROM_SYSTEM, 116 NULL, err, 117 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 118 (LPTSTR) &lpMsgBuf, 0, NULL ); 119 num = lstrlen((LPCTSTR)lpMsgBuf); 120 if (num < 1) 121 return b; 122 num = (num < max_b_len) ? num : (max_b_len - 1); 123 for (k = 0; k < num; ++k) { 124 ch = *((LPCTSTR)lpMsgBuf + k); 125 if ((ch >= 0x0) && (ch < 0x7f)) 126 b[k] = ch & 0x7f; 127 else 128 b[k] = '?'; 129 } 130 return b; 131} 132 133static int findElemIndex(UCHAR port_num, UCHAR bus, UCHAR target, UCHAR lun) 134{ 135 int k; 136 struct w_scsi_elem * sep; 137 138 for (k = 0; k < next_unused_scsi_elem; ++k) { 139 sep = w_scsi_arr + k; 140 if ((port_num == sep->port_num) && (bus == sep->bus) && 141 (target == sep->target) && (lun == sep->lun)) 142 return k; 143#if 0 144 if (port_num < sep->port_num) 145 break; /* assume port_num sorted ascending */ 146#endif 147 } 148 return -1; 149} 150 151static BOOL fetchInquiry(HANDLE fh, unsigned char * resp, int max_resp_len, 152 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER * afterCall, 153 int verbose) 154{ 155 BOOL success; 156 int len; 157 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptdw; 158 ULONG dummy; /* also acts to align next array */ 159 BYTE inqResp[SCSI2_INQ_RESP_LEN]; 160 unsigned char inqCdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 161 SCSI2_INQ_RESP_LEN, 0}; 162 DWORD err; 163 char b[256]; 164 165 memset(&sptdw, 0, sizeof(sptdw)); 166 memset(inqResp, 0, sizeof(inqResp)); 167 sptdw.spt.Length = sizeof (SCSI_PASS_THROUGH_DIRECT); 168 sptdw.spt.CdbLength = sizeof(inqCdb); 169 sptdw.spt.SenseInfoLength = SCSI_MAX_SENSE_LEN; 170 sptdw.spt.DataIn = SCSI_IOCTL_DATA_IN; 171 sptdw.spt.DataTransferLength = SCSI2_INQ_RESP_LEN; 172 sptdw.spt.TimeOutValue = DEF_TIMEOUT; 173 sptdw.spt.DataBuffer = inqResp; 174 sptdw.spt.SenseInfoOffset = 175 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); 176 memcpy(sptdw.spt.Cdb, inqCdb, sizeof(inqCdb)); 177 178 success = DeviceIoControl(fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, 179 &sptdw, sizeof(sptdw), 180 &sptdw, sizeof(sptdw), 181 &dummy, NULL); 182 if (! success) { 183 if (verbose) { 184 err = GetLastError(); 185 fprintf(stderr, "fetchInquiry: DeviceIoControl for INQUIRY, " 186 "err=%lu\n\t%s", err, get_err_str(err, sizeof(b), b)); 187 } 188 return success; 189 } 190 if (afterCall) 191 memcpy(afterCall, &sptdw, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)); 192 if (resp) { 193 len = (SCSI2_INQ_RESP_LEN > max_resp_len) ? 194 max_resp_len : SCSI2_INQ_RESP_LEN; 195 memcpy(resp, inqResp, len); 196 } 197 return success; 198} 199 200int sg_do_wscan(char letter, int verbose) 201{ 202 int k, j, m, hole_count, index, matched; 203 DWORD err; 204 HANDLE fh; 205 ULONG dummy; 206 BOOL success; 207 BYTE bus; 208 PSCSI_ADAPTER_BUS_INFO ai; 209 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptdw; 210 unsigned char inqResp[SCSI2_INQ_RESP_LEN]; 211 char adapter_name[64]; 212 char inqDataBuff[2048]; 213 char b[256]; 214 struct w_scsi_elem * sep; 215 216 memset(w_scsi_arr, 0, sizeof(w_scsi_arr)); 217 hole_count = 0; 218 for (k = 0; k < MAX_ADAPTER_NUM; ++k) { 219 snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\SCSI%d:", k); 220 fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE, 221 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 222 OPEN_EXISTING, 0, NULL); 223 if (fh != INVALID_HANDLE_VALUE) { 224 hole_count = 0; 225 success = DeviceIoControl(fh, IOCTL_SCSI_GET_INQUIRY_DATA, 226 NULL, 0, inqDataBuff, sizeof(inqDataBuff), 227 &dummy, FALSE); 228 if (success) { 229 PSCSI_BUS_DATA pbd; 230 PSCSI_INQUIRY_DATA pid; 231 int num_lus, off, len; 232 233 ai = (PSCSI_ADAPTER_BUS_INFO)inqDataBuff; 234 for (bus = 0; bus < ai->NumberOfBusses; bus++) { 235 pbd = ai->BusData + bus; 236 num_lus = pbd->NumberOfLogicalUnits; 237 off = pbd->InquiryDataOffset; 238 for (j = 0; j < num_lus; ++j) { 239 if ((off < (int)sizeof(SCSI_ADAPTER_BUS_INFO)) || 240 (off > ((int)sizeof(inqDataBuff) - 241 (int)sizeof(SCSI_INQUIRY_DATA)))) 242 break; 243 pid = (PSCSI_INQUIRY_DATA)(inqDataBuff + off); 244 m = next_unused_scsi_elem++; 245 if (next_unused_scsi_elem > MAX_SCSI_ELEMS) { 246 fprintf(stderr, "Too many scsi devices (more " 247 "than %d)\n", MAX_SCSI_ELEMS); 248 return SG_LIB_CAT_OTHER; 249 } 250 next_elem_after_scsi_adapter_valid = 251 next_unused_scsi_elem; 252 sep = w_scsi_arr + m; 253 sep->in_use = 1; 254 sep->scsi_adapter_valid = 1; 255 sep->port_num = k; 256 sep->bus = pid->PathId; 257 sep->target = pid->TargetId; 258 sep->lun = pid->Lun; 259 sep->device_claimed = pid->DeviceClaimed; 260 len = pid->InquiryDataLength; 261 len = (len > SCSI2_INQ_RESP_LEN) ? 262 SCSI2_INQ_RESP_LEN : len; 263 memcpy(sep->inq_resp, pid->InquiryData, len); 264 sep->pdt = sep->inq_resp[0] & 0x3f; 265 if (0 == sep->inq_resp[4]) 266 sep->dubious_scsi = 1; 267 268 if (verbose > 1) { 269 fprintf(stderr, "%s: PathId=%d TargetId=%d Lun=%d ", 270 adapter_name, pid->PathId, pid->TargetId, pid->Lun); 271 fprintf(stderr, " DeviceClaimed=%d\n", pid->DeviceClaimed); 272 dStrHex((const char *)(pid->InquiryData), pid->InquiryDataLength, 0); 273 } 274 off = pid->NextInquiryDataOffset; 275 } 276 } 277 } else { 278 err = GetLastError(); 279 fprintf(stderr, "%s: IOCTL_SCSI_GET_INQUIRY_DATA failed " 280 "err=%lu\n\t%s", 281 adapter_name, err, get_err_str(err, sizeof(b), b)); 282 } 283 CloseHandle(fh); 284 } else { 285 if (verbose > 2) { 286 err = GetLastError(); 287 fprintf(stderr, "%s: CreateFile failed err=%lu\n\t%s", 288 adapter_name, err, get_err_str(err, sizeof(b), b)); 289 } 290 if (++hole_count >= MAX_HOLE_COUNT) 291 break; 292 } 293 } 294 295 for (k = 0; k < 24; ++k) { 296 matched = 0; 297 sep = NULL; 298 snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\%c:", 'C' + k); 299 fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE, 300 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 301 OPEN_EXISTING, 0, NULL); 302 if (fh != INVALID_HANDLE_VALUE) { 303 success = DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS, 304 NULL, 0, inqDataBuff, sizeof(inqDataBuff), 305 &dummy, FALSE); 306 if (success) { 307 PSCSI_ADDRESS pa; 308 309 pa = (PSCSI_ADDRESS)inqDataBuff; 310 index = findElemIndex(pa->PortNumber, pa->PathId, 311 pa->TargetId, pa->Lun); 312 if (index >= 0) { 313 sep = w_scsi_arr + index; 314 matched = 1; 315 } else { 316 m = next_unused_scsi_elem++; 317 if (next_unused_scsi_elem > MAX_SCSI_ELEMS) { 318 fprintf(stderr, "Too many scsi devices (more " 319 "than %d)\n", MAX_SCSI_ELEMS); 320 return SG_LIB_CAT_OTHER; 321 } 322 sep = w_scsi_arr + m; 323 sep->in_use = 1; 324 sep->port_num = pa->PortNumber; 325 sep->bus = pa->PathId; 326 sep->target = pa->TargetId; 327 sep->lun = pa->Lun; 328 sep->device_claimed = 1; 329 } 330 if (sep->volume_valid) { 331 sep->volume_multiple = 1; 332 if (('C' + k) == letter) 333 sep->volume_letter = letter; 334 } else { 335 sep->volume_valid = 1; 336 sep->volume_letter = 'C' + k; 337 } 338 if (verbose > 1) 339 fprintf(stderr, "%c: PortNum=%d PathId=%d TargetId=%d " 340 "Lun=%d index=%d\n", 'C' + k, pa->PortNumber, 341 pa->PathId, pa->TargetId, pa->Lun, index); 342 if (matched) { 343 CloseHandle(fh); 344 continue; 345 } 346 } else { 347 if (verbose > 1) { 348 err = GetLastError(); 349 fprintf(stderr, "%c: IOCTL_SCSI_GET_ADDRESS err=%lu\n\t" 350 "%s", 'C' + k, err, get_err_str(err, sizeof(b), b)); 351 } 352 } 353 if (fetchInquiry(fh, inqResp, sizeof(inqResp), &sptdw, 354 verbose)) { 355 if (sptdw.spt.ScsiStatus) { 356 if (verbose) { 357 fprintf(stderr, "%c: INQUIRY failed: ", 'C' + k); 358 sg_print_scsi_status(sptdw.spt.ScsiStatus); 359 sg_print_sense(" ", sptdw.ucSenseBuf, 360 sizeof(sptdw.ucSenseBuf), 0); 361 } 362 CloseHandle(fh); 363 continue; 364 } 365 if (NULL == sep) { 366 m = next_unused_scsi_elem++; 367 if (next_unused_scsi_elem > MAX_SCSI_ELEMS) { 368 fprintf(stderr, "Too many scsi devices (more " 369 "than %d)\n", MAX_SCSI_ELEMS); 370 return SG_LIB_CAT_OTHER; 371 } 372 sep = w_scsi_arr + m; 373 sep->in_use = 1; 374 sep->device_claimed = 1; 375 sep->volume_valid = 1; 376 sep->volume_letter = 'C' + k; 377 } 378 memcpy(sep->inq_resp, inqResp, sizeof(sep->inq_resp)); 379 sep->pdt = sep->inq_resp[0] & 0x3f; 380 if (0 == sep->inq_resp[4]) 381 sep->dubious_scsi = 1; 382 } 383 CloseHandle(fh); 384 } 385 } 386 387 hole_count = 0; 388 for (k = 0; k < MAX_PHYSICALDRIVE_NUM; ++k) { 389 matched = 0; 390 sep = NULL; 391 snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\PhysicalDrive%d", k); 392 fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE, 393 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 394 OPEN_EXISTING, 0, NULL); 395 if (fh != INVALID_HANDLE_VALUE) { 396 hole_count = 0; 397 success = DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS, 398 NULL, 0, inqDataBuff, sizeof(inqDataBuff), 399 &dummy, FALSE); 400 if (success) { 401 PSCSI_ADDRESS pa; 402 403 pa = (PSCSI_ADDRESS)inqDataBuff; 404 index = findElemIndex(pa->PortNumber, pa->PathId, 405 pa->TargetId, pa->Lun); 406 if (index >= 0) { 407 sep = w_scsi_arr + index; 408 matched = 1; 409 } else { 410 m = next_unused_scsi_elem++; 411 if (next_unused_scsi_elem > MAX_SCSI_ELEMS) { 412 fprintf(stderr, "Too many scsi devices (more " 413 "than %d)\n", MAX_SCSI_ELEMS); 414 return SG_LIB_CAT_OTHER; 415 } 416 sep = w_scsi_arr + m; 417 sep->in_use = 1; 418 sep->port_num = pa->PortNumber; 419 sep->bus = pa->PathId; 420 sep->target = pa->TargetId; 421 sep->lun = pa->Lun; 422 sep->device_claimed = 1; 423 } 424 sep->physicaldrive_valid = 1; 425 sep->physicaldrive_num = k; 426 if (verbose > 1) 427 fprintf(stderr, "PD%d: PortNum=%d PathId=%d TargetId=%d " 428 "Lun=%d index=%d\n", k, pa->PortNumber, 429 pa->PathId, pa->TargetId, pa->Lun, index); 430 if (matched) { 431 CloseHandle(fh); 432 continue; 433 } 434 } else { 435 if (verbose > 1) { 436 err = GetLastError(); 437 fprintf(stderr, "PD%d: IOCTL_SCSI_GET_ADDRESS err=%lu\n\t" 438 "%s", k, err, get_err_str(err, sizeof(b), b)); 439 } 440 } 441 if (fetchInquiry(fh, inqResp, sizeof(inqResp), &sptdw, 442 verbose)) { 443 if (sptdw.spt.ScsiStatus) { 444 if (verbose) { 445 fprintf(stderr, "PD%d: INQUIRY failed: ", k); 446 sg_print_scsi_status(sptdw.spt.ScsiStatus); 447 sg_print_sense(" ", sptdw.ucSenseBuf, 448 sizeof(sptdw.ucSenseBuf), 0); 449 } 450 CloseHandle(fh); 451 continue; 452 } 453 if (NULL == sep) { 454 m = next_unused_scsi_elem++; 455 if (next_unused_scsi_elem > MAX_SCSI_ELEMS) { 456 fprintf(stderr, "Too many scsi devices (more " 457 "than %d)\n", MAX_SCSI_ELEMS); 458 return SG_LIB_CAT_OTHER; 459 } 460 sep = w_scsi_arr + m; 461 sep->in_use = 1; 462 sep->device_claimed = 1; 463 sep->physicaldrive_valid = 1; 464 sep->physicaldrive_num = k; 465 } 466 memcpy(sep->inq_resp, inqResp, sizeof(sep->inq_resp)); 467 sep->pdt = sep->inq_resp[0] & 0x3f; 468 if (0 == sep->inq_resp[4]) 469 sep->dubious_scsi = 1; 470 } 471 CloseHandle(fh); 472 } else { 473 if (verbose > 2) { 474 err = GetLastError(); 475 fprintf(stderr, "%s: CreateFile failed err=%lu\n\t%s", 476 adapter_name, err, get_err_str(err, sizeof(b), b)); 477 } 478 if (++hole_count >= MAX_HOLE_COUNT) 479 break; 480 } 481 } 482 483 hole_count = 0; 484 for (k = 0; k < MAX_CDROM_NUM; ++k) { 485 matched = 0; 486 sep = NULL; 487 snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\CDROM%d", k); 488 fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE, 489 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 490 OPEN_EXISTING, 0, NULL); 491 if (fh != INVALID_HANDLE_VALUE) { 492 hole_count = 0; 493 success = DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS, 494 NULL, 0, inqDataBuff, sizeof(inqDataBuff), 495 &dummy, FALSE); 496 if (success) { 497 PSCSI_ADDRESS pa; 498 499 pa = (PSCSI_ADDRESS)inqDataBuff; 500 index = findElemIndex(pa->PortNumber, pa->PathId, 501 pa->TargetId, pa->Lun); 502 if (index >= 0) { 503 sep = w_scsi_arr + index; 504 matched = 1; 505 } else { 506 m = next_unused_scsi_elem++; 507 if (next_unused_scsi_elem > MAX_SCSI_ELEMS) { 508 fprintf(stderr, "Too many scsi devices (more " 509 "than %d)\n", MAX_SCSI_ELEMS); 510 return SG_LIB_CAT_OTHER; 511 } 512 sep = w_scsi_arr + m; 513 sep->in_use = 1; 514 sep->port_num = pa->PortNumber; 515 sep->bus = pa->PathId; 516 sep->target = pa->TargetId; 517 sep->lun = pa->Lun; 518 sep->device_claimed = 1; 519 } 520 sep->cdrom_valid = 1; 521 sep->cdrom_num = k; 522 if (verbose > 1) 523 fprintf(stderr, "CDROM%d: PortNum=%d PathId=%d TargetId=%d " 524 "Lun=%d index=%d\n", k, pa->PortNumber, 525 pa->PathId, pa->TargetId, pa->Lun, index); 526 if (matched) { 527 CloseHandle(fh); 528 continue; 529 } 530 } else { 531 if (verbose > 1) { 532 err = GetLastError(); 533 fprintf(stderr, "CDROM%d: IOCTL_SCSI_GET_ADDRESS err=%lu\n\t" 534 "%s", k, err, get_err_str(err, sizeof(b), b)); 535 } 536 } 537 if (fetchInquiry(fh, inqResp, sizeof(inqResp), &sptdw, 538 verbose)) { 539 if (sptdw.spt.ScsiStatus) { 540 if (verbose) { 541 fprintf(stderr, "CDROM%d: INQUIRY failed: ", k); 542 sg_print_scsi_status(sptdw.spt.ScsiStatus); 543 sg_print_sense(" ", sptdw.ucSenseBuf, 544 sizeof(sptdw.ucSenseBuf), 0); 545 } 546 CloseHandle(fh); 547 continue; 548 } 549 if (NULL == sep) { 550 m = next_unused_scsi_elem++; 551 if (next_unused_scsi_elem > MAX_SCSI_ELEMS) { 552 fprintf(stderr, "Too many scsi devices (more " 553 "than %d)\n", MAX_SCSI_ELEMS); 554 return SG_LIB_CAT_OTHER; 555 } 556 sep = w_scsi_arr + m; 557 sep->in_use = 1; 558 sep->device_claimed = 1; 559 sep->cdrom_valid = 1; 560 sep->cdrom_num = k; 561 } 562 memcpy(sep->inq_resp, inqResp, sizeof(sep->inq_resp)); 563 sep->pdt = sep->inq_resp[0] & 0x3f; 564 if (0 == sep->inq_resp[4]) 565 sep->dubious_scsi = 1; 566 } 567 CloseHandle(fh); 568 } else { 569 if (verbose > 3) { 570 err = GetLastError(); 571 fprintf(stderr, "%s: CreateFile failed err=%lu\n\t%s", 572 adapter_name, err, get_err_str(err, sizeof(b), b)); 573 } 574 if (++hole_count >= MAX_HOLE_COUNT) 575 break; 576 } 577 } 578 579 hole_count = 0; 580 for (k = 0; k < MAX_TAPE_NUM; ++k) { 581 matched = 0; 582 sep = NULL; 583 snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\TAPE%d", k); 584 fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE, 585 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 586 OPEN_EXISTING, 0, NULL); 587 if (fh != INVALID_HANDLE_VALUE) { 588 hole_count = 0; 589 success = DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS, 590 NULL, 0, inqDataBuff, sizeof(inqDataBuff), 591 &dummy, FALSE); 592 if (success) { 593 PSCSI_ADDRESS pa; 594 595 pa = (PSCSI_ADDRESS)inqDataBuff; 596 index = findElemIndex(pa->PortNumber, pa->PathId, 597 pa->TargetId, pa->Lun); 598 if (index >= 0) { 599 sep = w_scsi_arr + index; 600 matched = 1; 601 } else { 602 m = next_unused_scsi_elem++; 603 if (next_unused_scsi_elem > MAX_SCSI_ELEMS) { 604 fprintf(stderr, "Too many scsi devices (more " 605 "than %d)\n", MAX_SCSI_ELEMS); 606 return SG_LIB_CAT_OTHER; 607 } 608 sep = w_scsi_arr + m; 609 sep->in_use = 1; 610 sep->port_num = pa->PortNumber; 611 sep->bus = pa->PathId; 612 sep->target = pa->TargetId; 613 sep->lun = pa->Lun; 614 sep->device_claimed = 1; 615 } 616 sep->tape_valid = 1; 617 sep->tape_num = k; 618 if (verbose > 1) 619 fprintf(stderr, "TAPE%d: PortNum=%d PathId=%d TargetId=%d " 620 "Lun=%d index=%d\n", k, pa->PortNumber, 621 pa->PathId, pa->TargetId, pa->Lun, index); 622 if (matched) { 623 CloseHandle(fh); 624 continue; 625 } 626 } else { 627 if (verbose > 1) { 628 err = GetLastError(); 629 fprintf(stderr, "TAPE%d: IOCTL_SCSI_GET_ADDRESS " 630 "err=%lu\n\t%s", k, err, 631 get_err_str(err, sizeof(b), b)); 632 } 633 } 634 if (fetchInquiry(fh, inqResp, sizeof(inqResp), &sptdw, 635 verbose)) { 636 if (sptdw.spt.ScsiStatus) { 637 if (verbose) { 638 fprintf(stderr, "TAPE%d: INQUIRY failed: ", k); 639 sg_print_scsi_status(sptdw.spt.ScsiStatus); 640 sg_print_sense(" ", sptdw.ucSenseBuf, 641 sizeof(sptdw.ucSenseBuf), 0); 642 } 643 CloseHandle(fh); 644 continue; 645 } 646 if (NULL == sep) { 647 m = next_unused_scsi_elem++; 648 if (next_unused_scsi_elem > MAX_SCSI_ELEMS) { 649 fprintf(stderr, "Too many scsi devices (more " 650 "than %d)\n", MAX_SCSI_ELEMS); 651 return SG_LIB_CAT_OTHER; 652 } 653 sep = w_scsi_arr + m; 654 sep->in_use = 1; 655 sep->device_claimed = 1; 656 sep->tape_valid = 1; 657 sep->tape_num = k; 658 } 659 memcpy(sep->inq_resp, inqResp, sizeof(sep->inq_resp)); 660 sep->pdt = sep->inq_resp[0] & 0x3f; 661 if (0 == sep->inq_resp[4]) 662 sep->dubious_scsi = 1; 663 } 664 CloseHandle(fh); 665 } else { 666 if (verbose > 4) { 667 err = GetLastError(); 668 fprintf(stderr, "%s: CreateFile failed err=%lu\n\t%s", 669 adapter_name, err, get_err_str(err, sizeof(b), b)); 670 } 671 if (++hole_count >= MAX_HOLE_COUNT) 672 break; 673 } 674 } 675 676 for (k = 0; k < MAX_SCSI_ELEMS; ++k) { 677 sep = w_scsi_arr + k; 678 if (0 == sep->in_use) 679 break; 680 if (sep->scsi_adapter_valid) { 681 snprintf(b, sizeof(b), "SCSI%d:%d,%d,%d ", sep->port_num, 682 sep->bus, sep->target, sep->lun); 683 printf("%-18s", b); 684 } else 685 printf(" "); 686 if (sep->volume_valid) 687 printf("%c: %c ", sep->volume_letter, 688 (sep->volume_multiple ? '+' : ' ')); 689 else 690 printf(" "); 691 if (sep->physicaldrive_valid) { 692 snprintf(b, sizeof(b), "PD%d ", sep->physicaldrive_num); 693 printf("%-9s", b); 694 } else if (sep->cdrom_valid) { 695 snprintf(b, sizeof(b), "CDROM%d ", sep->cdrom_num); 696 printf("%-9s", b); 697 } else if (sep->tape_valid) { 698 snprintf(b, sizeof(b), "TAPE%d ", sep->tape_num); 699 printf("%-9s", b); 700 } else 701 printf(" "); 702 703 memcpy(b, sep->inq_resp + 8, SCSI2_INQ_RESP_LEN); 704 for (j = 0; j < 28; ++j) { 705 if ((b[j] < 0x20) || (b[j] > 0x7e)) 706 b[j] = ' '; 707 } 708 b[28] = '\0'; 709 printf("%-30s", b); 710 if (sep->dubious_scsi) 711 printf("* "); 712 else if ((! sep->physicaldrive_valid) && (! sep->cdrom_valid) && 713 (! sep->tape_valid)) 714 printf("pdt=%-2d", sep->pdt); 715 else 716 printf(" "); 717 718 printf("\n"); 719 } 720 return 0; 721} 722