1 /* $NetBSD: iscsic_driverif.c,v 1.7 2025/12/23 16:36:12 nia Exp $ */ 2 3 /*- 4 * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Wasabi Systems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "iscsic_globals.h" 33 34 #include <ctype.h> 35 #include <endian.h> 36 #include <inttypes.h> 37 38 typedef struct { 39 uint8_t asc; 40 uint8_t ascq; 41 const char *key; 42 } asc_tab_t; 43 44 asc_tab_t asctab[] = { 45 {0x00, 0x01, "FILEMARK DETECTED"}, 46 {0x00, 0x02, "END-OF-PARTITION/MEDIUM DETECTED"}, 47 {0x00, 0x03, "SETMARK DETECTED"}, 48 {0x00, 0x04, "BEGINNING-OF-PARTITION/MEDIUM DETECTED"}, 49 {0x00, 0x05, "END-OF-DATA DETECTED"}, 50 {0x00, 0x06, "I/O PROCESS TERMINATED"}, 51 {0x00, 0x11, "AUDIO PLAY OPERATION IN PROGRESS"}, 52 {0x00, 0x12, "AUDIO PLAY OPERATION PAUSED"}, 53 {0x00, 0x13, "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED"}, 54 {0x00, 0x14, "AUDIO PLAY OPERATION STOPPED DUE TO ERROR"}, 55 {0x00, 0x15, "NO CURRENT AUDIO STATUS TO RETURN"}, 56 {0x01, 0x00, "NO INDEX/SECTOR SIGNAL"}, 57 {0x02, 0x00, "NO SEEK COMPLETE"}, 58 {0x03, 0x00, "PERIPHERAL DEVICE WRITE FAULT"}, 59 {0x03, 0x01, "NO WRITE CURRENT"}, 60 {0x03, 0x02, "EXCESSIVE WRITE ERRORS"}, 61 {0x04, 0x00, "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE"}, 62 {0x04, 0x01, "LOGICAL UNIT IS IN PROCESS OF BECOMING READY"}, 63 {0x04, 0x02, "LOGICAL UNIT NOT READY, INITIALIZING COMMAND REQUIRED"}, 64 {0x04, 0x03, "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED"}, 65 {0x04, 0x04, "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS"}, 66 {0x05, 0x00, "LOGICAL UNIT DOES NOT RESPOND TO SELECTION"}, 67 {0x06, 0x00, "NO REFERENCE POSITION FOUND"}, 68 {0x07, 0x00, "MULTIPLE PERIPHERAL DEVICES SELECTED"}, 69 {0x08, 0x00, "LOGICAL UNIT COMMUNICATION FAILURE"}, 70 {0x08, 0x01, "LOGICAL UNIT COMMUNICATION TIME-OUT"}, 71 {0x08, 0x02, "LOGICAL UNIT COMMUNICATION PARITY ERROR"}, 72 {0x09, 0x00, "TRACK FOLLOWING ERROR"}, 73 {0x09, 0x01, "TRACKING SERVO FAILURE"}, 74 {0x09, 0x02, "FOCUS SERVO FAILURE"}, 75 {0x09, 0x03, "SPINDLE SERVO FAILURE"}, 76 {0x0A, 0x00, "ERROR LOG OVERFLOW"}, 77 {0x0C, 0x00, "WRITE ERROR"}, 78 {0x0C, 0x01, "WRITE ERROR RECOVERED WITH AUTO REALLOCATION"}, 79 {0x0C, 0x02, "WRITE ERROR - AUTO REALLOCATION FAILED"}, 80 {0x10, 0x00, "ID CRC OR ECC ERROR"}, 81 {0x11, 0x00, "UNRECOVERED READ ERROR"}, 82 {0x11, 0x01, "READ RETRIES EXHAUSTED"}, 83 {0x11, 0x02, "ERROR TOO LONG TO CORRECT"}, 84 {0x11, 0x03, "MULTIPLE READ ERRORS"}, 85 {0x11, 0x04, "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED"}, 86 {0x11, 0x05, "L-EC UNCORRECTABLE ERROR"}, 87 {0x11, 0x06, "CIRC UNRECOVERED ERROR"}, 88 {0x11, 0x07, "DATA RESYNCHRONIZATION ERROR"}, 89 {0x11, 0x08, "INCOMPLETE BLOCK READ"}, 90 {0x11, 0x09, "NO GAP FOUND"}, 91 {0x11, 0x0A, "MISCORRECTED ERROR"}, 92 {0x11, 0x0B, "UNRECOVERED READ ERROR - RECOMMEND REASSIGNMENT"}, 93 {0x11, 0x0C, "UNRECOVERED READ ERROR - RECOMMEND REWRITE THE DATA"}, 94 {0x12, 0x00, "ADDRESS MARK NOT FOUND FOR ID FIELD"}, 95 {0x13, 0x00, "ADDRESS MARK NOT FOUND FOR DATA FIELD"}, 96 {0x14, 0x00, "RECORDED ENTITY NOT FOUND"}, 97 {0x14, 0x01, "RECORD NOT FOUND"}, 98 {0x14, 0x02, "FILEMARK OR SETMARK NOT FOUND"}, 99 {0x14, 0x03, "END-OF-DATA NOT FOUND"}, 100 {0x14, 0x04, "BLOCK SEQUENCE ERROR"}, 101 {0x15, 0x00, "RANDOM POSITIONING ERROR"}, 102 {0x15, 0x01, "MECHANICAL POSITIONING ERROR"}, 103 {0x15, 0x02, "POSITIONING ERROR DETECTED BY READ OF MEDIUM"}, 104 {0x16, 0x00, "DATA SYNCHRONIZATION MARK ERROR"}, 105 {0x17, 0x00, "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED"}, 106 {0x17, 0x01, "RECOVERED DATA WITH RETRIES"}, 107 {0x17, 0x02, "RECOVERED DATA WITH POSITIVE HEAD OFFSET"}, 108 {0x17, 0x03, "RECOVERED DATA WITH NEGATIVE HEAD OFFSET"}, 109 {0x17, 0x04, "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED"}, 110 {0x17, 0x05, "RECOVERED DATA USING PREVIOUS SECTOR ID"}, 111 {0x17, 0x06, "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED"}, 112 {0x17, 0x07, "RECOVERED DATA WITHOUT ECC - RECOMMEND REASSIGNMENT"}, 113 {0x17, 0x08, "RECOVERED DATA WITHOUT ECC - RECOMMEND REWRITE"}, 114 {0x18, 0x00, "RECOVERED DATA WITH ERROR CORRECTION APPLIED"}, 115 {0x18, 0x01, "RECOVERED DATA WITH ERROR CORRECTION & RETRIES APPLIED"}, 116 {0x18, 0x02, "RECOVERED DATA - DATA AUTO-REALLOCATED"}, 117 {0x18, 0x03, "RECOVERED DATA WITH CIRC"}, 118 {0x18, 0x04, "RECOVERED DATA WITH L-EC"}, 119 {0x18, 0x05, "RECOVERED DATA - RECOMMEND REASSIGNMENT"}, 120 {0x18, 0x06, "RECOVERED DATA - RECOMMEND REWRITE"}, 121 {0x19, 0x00, "DEFECT LIST ERROR"}, 122 {0x19, 0x01, "DEFECT LIST NOT AVAILABLE"}, 123 {0x19, 0x02, "DEFECT LIST ERROR IN PRIMARY LIST"}, 124 {0x19, 0x03, "DEFECT LIST ERROR IN GROWN LIST"}, 125 {0x1A, 0x00, "PARAMETER LIST LENGTH ERROR"}, 126 {0x1B, 0x00, "SYNCHRONOUS DATA TRANSFER ERROR"}, 127 {0x1C, 0x00, "DEFECT LIST NOT FOUND"}, 128 {0x1C, 0x01, "PRIMARY DEFECT LIST NOT FOUND"}, 129 {0x1C, 0x02, "GROWN DEFECT LIST NOT FOUND"}, 130 {0x1D, 0x00, "MISCOMPARE DURING VERIFY OPERATION"}, 131 {0x1E, 0x00, "RECOVERED ID WITH ECC CORRECTION"}, 132 {0x20, 0x00, "INVALID COMMAND OPERATION CODE"}, 133 {0x21, 0x00, "LOGICAL BLOCK ADDRESS OUT OF RANGE"}, 134 {0x21, 0x01, "INVALID ELEMENT ADDRESS"}, 135 {0x22, 0x00, "ILLEGAL FUNCTION"}, 136 {0x24, 0x00, "INVALID FIELD IN CDB"}, 137 {0x25, 0x00, "LOGICAL UNIT NOT SUPPORTED"}, 138 {0x26, 0x00, "INVALID FIELD IN PARAMETER LIST"}, 139 {0x26, 0x01, "PARAMETER NOT SUPPORTED"}, 140 {0x26, 0x02, "PARAMETER VALUE INVALID"}, 141 {0x26, 0x03, "THRESHOLD PARAMETERS NOT SUPPORTED"}, 142 {0x27, 0x00, "WRITE PROTECTED"}, 143 {0x28, 0x00, "NOT READY TO READY TRANSITION, MEDIUM MAY HAVE CHANGED"}, 144 {0x28, 0x01, "IMPORT OR EXPORT ELEMENT ACCESSED"}, 145 {0x29, 0x00, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"}, 146 {0x2A, 0x00, "PARAMETERS CHANGED"}, 147 {0x2A, 0x01, "MODE PARAMETERS CHANGED"}, 148 {0x2A, 0x02, "LOG PARAMETERS CHANGED"}, 149 {0x2B, 0x00, "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT"}, 150 {0x2C, 0x00, "COMMAND SEQUENCE ERROR"}, 151 {0x2C, 0x01, "TOO MANY WINDOWS SPECIFIED"}, 152 {0x2C, 0x02, "INVALID COMBINATION OF WINDOWS SPECIFIED"}, 153 {0x2D, 0x00, "OVERWRITE ERROR ON UPDATE IN PLACE"}, 154 {0x2F, 0x00, "COMMANDS CLEARED BY ANOTHER INITIATOR"}, 155 {0x30, 0x00, "INCOMPATIBLE MEDIUM INSTALLED"}, 156 {0x30, 0x01, "CANNOT READ MEDIUM - UNKNOWN FORMAT"}, 157 {0x30, 0x02, "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT"}, 158 {0x30, 0x03, "CLEANING CARTRIDGE INSTALLED"}, 159 {0x31, 0x00, "MEDIUM FORMAT CORRUPTED"}, 160 {0x31, 0x01, "FORMAT COMMAND FAILED"}, 161 {0x32, 0x00, "NO DEFECT SPARE LOCATION AVAILABLE"}, 162 {0x32, 0x01, "DEFECT LIST UPDATE FAILURE"}, 163 {0x33, 0x00, "TAPE LENGTH ERROR"}, 164 {0x36, 0x00, "RIBBON, INK, OR TONER FAILURE"}, 165 {0x37, 0x00, "ROUNDED PARAMETER"}, 166 {0x39, 0x00, "SAVING PARAMETERS NOT SUPPORTED"}, 167 {0x3A, 0x00, "MEDIUM NOT PRESENT"}, 168 {0x3B, 0x00, "SEQUENTIAL POSITIONING ERROR"}, 169 {0x3B, 0x01, "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM"}, 170 {0x3B, 0x02, "TAPE POSITION ERROR AT END-OF-MEDIUM"}, 171 {0x3B, 0x03, "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY"}, 172 {0x3B, 0x04, "SLEW FAILURE"}, 173 {0x3B, 0x05, "PAPER JAM"}, 174 {0x3B, 0x06, "FAILED TO SENSE TOP-OF-FORM"}, 175 {0x3B, 0x07, "FAILED TO SENSE BOTTOM-OF-FORM"}, 176 {0x3B, 0x08, "REPOSITION ERROR"}, 177 {0x3B, 0x09, "READ PAST END OF MEDIUM"}, 178 {0x3B, 0x0A, "READ PAST BEGINNING OF MEDIUM"}, 179 {0x3B, 0x0B, "POSITION PAST END OF MEDIUM"}, 180 {0x3B, 0x0C, "POSITION PAST BEGINNING OF MEDIUM"}, 181 {0x3B, 0x0D, "MEDIUM DESTINATION ELEMENT FULL"}, 182 {0x3B, 0x0E, "MEDIUM SOURCE ELEMENT EMPTY"}, 183 {0x3D, 0x00, "INVALID BITS IN IDENTIFY MESSAGE"}, 184 {0x3E, 0x00, "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET"}, 185 {0x3F, 0x00, "TARGET OPERATING CONDITIONS HAVE CHANGED"}, 186 {0x3F, 0x01, "MICROCODE HAS BEEN CHANGED"}, 187 {0x3F, 0x02, "LPWRSOMC CHANGED OPERATING DEFINITION"}, 188 {0x3F, 0x03, "INQUIRY DATA HAS CHANGED"}, 189 {0x40, 0x00, "RAM FAILURE (SHOULD USE 40 NN)"}, 190 {0x41, 0x00, "DATA PATH FAILURE (SHOULD USE 40 NN)"}, 191 {0x42, 0x00, "POWER-ON OR SELF-TEST FAILURE (SHOULD USE 40 NN)"}, 192 {0x43, 0x00, "MESSAGE ERROR"}, 193 {0x44, 0x00, "INTERNAL TARGET FAILURE"}, 194 {0x45, 0x00, "SELECT OR RESELECT FAILURE"}, 195 {0x46, 0x00, "UNSUCCESSFUL SOFT RESET"}, 196 {0x47, 0x00, "SCSI PARITY ERROR"}, 197 {0x48, 0x00, "INITIATOR DETECTED ERROR MESSAGE RECEIVED"}, 198 {0x49, 0x00, "INVALID MESSAGE ERROR"}, 199 {0x4A, 0x00, "COMMAND PHASE ERROR"}, 200 {0x4B, 0x00, "DATA PHASE ERROR"}, 201 {0x4C, 0x00, "LOGICAL UNIT FAILED SELF-CONFIGURATION"}, 202 {0x4E, 0x00, "OVERLAPPED COMMANDS ATTEMPTED"}, 203 {0x50, 0x00, "WRITE APPEND ERROR"}, 204 {0x50, 0x01, "WRITE APPEND POSITION ERROR"}, 205 {0x50, 0x02, "POSITION ERROR RELATED TO TIMING"}, 206 {0x51, 0x00, "ERASE FAILURE"}, 207 {0x52, 0x00, "CARTRIDGE FAULT"}, 208 {0x53, 0x00, "MEDIA LOAD OR EJECT FAILED"}, 209 {0x53, 0x01, "UNLOAD TAPE FAILURE"}, 210 {0x53, 0x02, "MEDIUM REMOVAL PREVENTED"}, 211 {0x54, 0x00, "SCSI TO HOST SYSTEM INTERFACE FAILURE"}, 212 {0x55, 0x00, "SYSTEM RESOURCE FAILURE"}, 213 {0x57, 0x00, "UNABLE TO RECOVER TABLE-OF-CONTENTS"}, 214 {0x58, 0x00, "GENERATION DOES NOT EXIST"}, 215 {0x59, 0x00, "UPDATED BLOCK READ"}, 216 {0x5A, 0x00, "OPERATOR REQUEST OR STATE CHANGE INPUT (UNSPECIFIED)"}, 217 {0x5A, 0x01, "OPERATOR MEDIUM REMOVAL REQUEST"}, 218 {0x5A, 0x02, "OPERATOR SELECTED WRITE PROTECT"}, 219 {0x5A, 0x03, "OPERATOR SELECTED WRITE PERMIT"}, 220 {0x5B, 0x00, "LOG EXCEPTION"}, 221 {0x5B, 0x01, "THRESHOLD CONDITION MET"}, 222 {0x5B, 0x02, "LOG COUNTER AT MAXIMUM"}, 223 {0x5B, 0x03, "LOG LIST CODES EXHAUSTED"}, 224 {0x5C, 0x00, "RPL STATUS CHANGE"}, 225 {0x5C, 0x01, "SPINDLES SYNCHRONIZED"}, 226 {0x5C, 0x02, "SPINDLES NOT SYNCHRONIZED"}, 227 {0x60, 0x00, "LAMP FAILURE"}, 228 {0x61, 0x00, "VIDEO ACQUISITION ERROR"}, 229 {0x61, 0x01, "UNABLE TO ACQUIRE VIDEO"}, 230 {0x61, 0x02, "OUT OF FOCUS"}, 231 {0x62, 0x00, "SCAN HEAD POSITIONING ERROR"}, 232 {0x63, 0x00, "END OF USER AREA ENCOUNTERED ON THIS TRACK"}, 233 {0x64, 0x00, "ILLEGAL MODE FOR THIS TRACK"}, 234 {0x00, 0x00, NULL} 235 }; 236 237 /* 238 * get_sessid: 239 * Get session ID. Queries Daemon for numeric ID if the user specifies 240 * a symbolic session name. 241 * 242 * Parameter: argc, argv (shifted) 243 * 244 * Returns: session ID if OK - else it doesn't return at all. 245 */ 246 247 uint32_t 248 get_sessid(int argc, char **argv, int optional) 249 { 250 iscsid_sym_id_t sid; 251 iscsid_search_list_req_t srch; 252 iscsid_response_t *rsp; 253 254 if (!cl_get_id('I', &sid, argc, argv)) { 255 if (!optional) { 256 arg_missing("Session ID"); 257 } 258 return 0; 259 } 260 261 if (!sid.id) { 262 srch.list_kind = SESSION_LIST; 263 srch.search_kind = FIND_NAME; 264 strlcpy((char *)srch.strval, (char *)sid.name, sizeof(srch.strval)); 265 srch.intval = 0; 266 267 send_request(ISCSID_SEARCH_LIST, sizeof(srch), &srch); 268 rsp = get_response(FALSE); 269 if (rsp->status) 270 status_error_slist(rsp->status); 271 272 GET_SYM_ID(sid.id, rsp->parameter); 273 free_response(rsp); 274 } 275 return sid.id; 276 } 277 278 279 /* 280 * dump_data: 281 * Displays the returned data in hex and ASCII format. 282 * 283 * Parameter: 284 * title Title text for Dump. 285 * buf Buffer to dump. 286 * len Number of bytes in buffer. 287 */ 288 289 void 290 dump_data(const char *title, const void *buffer, size_t len) 291 { 292 const uint8_t *bp = buffer; 293 size_t i, nelem; 294 295 printf("%s\n", title); 296 297 while (len > 0) { 298 nelem = min(16, len); 299 printf(" "); 300 301 for (i = 0; i < nelem; i++) { 302 if (i >= len) 303 printf(" "); 304 else 305 printf("%02x ", bp[i]); 306 } 307 for (i = nelem; i < 16; i++) { 308 printf(" "); 309 } 310 printf(" '"); 311 for (i = 0; i < nelem; i++) { 312 if (i >= len) 313 break; 314 printf("%c", isprint(bp[i]) ? bp[i] : ' '); 315 } 316 printf("'\n"); 317 if (len < 16) 318 break; 319 len -= 16; 320 bp += 16; 321 } 322 } 323 324 325 /* 326 * add_asc_info: 327 * Examines additional sense code and qualifier, adds text to given string 328 * if it's in the table. 329 * 330 * Parameter: 331 * str The existing sense code string 332 * asc Additional sense code 333 * ascq Additional sense code qualifier 334 * 335 * Returns: the result string. 336 */ 337 338 STATIC char * 339 add_asc_info(char *str, uint8_t asc, uint8_t ascq) 340 { 341 asc_tab_t *pt; 342 char *bp; 343 344 for (pt = asctab; pt->key != NULL && asc >= pt->asc; pt++) { 345 if (asc == pt->asc && ascq == pt->ascq) { 346 bp = (char *)&buf[1024]; 347 snprintf(bp, sizeof(buf) - 1024, "%s: %s", 348 str, pt->key); 349 return bp; 350 } 351 } 352 return str; 353 } 354 355 356 /* 357 * do_ioctl: 358 * Executes the I/O command, evaluates the return code, and displays 359 * sense data if the command failed. 360 * 361 * Parameter: 362 * io The i/o command parameters. 363 * 364 * Returns: 0 if OK, else an error code. 365 */ 366 367 int 368 do_ioctl(iscsi_iocommand_parameters_t * io, int rd) 369 { 370 char *esp; 371 char es[64]; 372 int rc; 373 374 io->req.databuf = buf; 375 io->req.senselen = sizeof(io->req.sense); 376 io->req.senselen_used = 0; 377 io->req.flags = (rd) ? SCCMD_READ : SCCMD_WRITE; 378 379 rc = ioctl(driver, ISCSI_IO_COMMAND, io); 380 381 if (io->req.senselen_used) { 382 switch (io->req.sense[2] & 0x0f) { 383 case 0x01: 384 snprintf(esp = es, sizeof(es), "Recovered Error"); 385 break; 386 case 0x02: 387 snprintf(esp = es, sizeof(es), "Not Ready"); 388 break; 389 case 0x03: 390 snprintf(esp = es, sizeof(es), "Medium Error"); 391 break; 392 case 0x04: 393 snprintf(esp = es, sizeof(es), "Hardware Error"); 394 break; 395 case 0x05: 396 snprintf(esp = es, sizeof(es), "Illegal Request"); 397 break; 398 case 0x06: 399 snprintf(esp = es, sizeof(es), "Unit Attention"); 400 break; 401 case 0x07: 402 snprintf(esp = es, sizeof(es), "Data Protect"); 403 break; 404 case 0x08: 405 snprintf(esp = es, sizeof(es), "Blank Check"); 406 break; 407 default: 408 snprintf(esp = (char *)&buf[256], sizeof(buf) - 256, "Sense key 0x%x", 409 io->req.sense[2] & 0x0f); 410 break; 411 } 412 if (io->req.senselen_used >= 14) { 413 add_asc_info(esp, io->req.sense[12], io->req.sense[13]); 414 } 415 snprintf((char *)buf, sizeof(buf), "Sense Data (%s):", esp); 416 dump_data((char *)buf, io->req.sense, io->req.senselen_used); 417 return io->req.retsts; 418 } 419 420 if (io->status) { 421 status_error(io->status); 422 } 423 if (rc) { 424 io_error("I/O command"); 425 } 426 return 0; 427 } 428 429 430 /* 431 * inquiry: 432 * Handle the inquiry command. 433 * 434 * Parameter: argc, argv (shifted) 435 * 436 * Returns: 0 if OK - else it doesn't return at all. 437 */ 438 439 int 440 inquiry(int argc, char **argv) 441 { 442 iscsi_iocommand_parameters_t io; 443 char opt; 444 int pag, rc; 445 446 (void) memset(&io, 0x0, sizeof(io)); 447 if ((io.session_id = get_sessid(argc, argv, FALSE)) == 0) { 448 return 1; 449 } 450 io.lun = cl_get_longlong('l', argc, argv); 451 452 opt = cl_get_char('d', argc, argv); 453 switch (opt) { 454 case 0: 455 case '0': 456 opt = 0; 457 break; 458 459 case 'p': 460 case 'P': 461 io.req.cmd[1] = 0x01; 462 opt = 1; 463 break; 464 465 case 'c': 466 case 'C': 467 io.req.cmd[1] = 0x02; 468 opt = 2; 469 break; 470 471 default: 472 gen_error("Invalid detail option '%c'\n", opt); 473 } 474 475 pag = cl_get_int('p', argc, argv); 476 477 check_extra_args(argc, argv); 478 479 io.req.cmdlen = 6; 480 io.req.cmd[0] = 0x12; 481 io.req.cmd[2] = (uint8_t) pag; 482 io.req.cmd[4] = 0xff; 483 484 io.req.datalen = 0xff; 485 486 if ((rc = do_ioctl(&io, TRUE)) != 0) { 487 return rc; 488 } 489 if (!io.req.datalen_used) { 490 printf("No Data!\n"); 491 return 1; 492 } 493 dump_data("Inquiry Data:", buf, io.req.datalen_used); 494 return 0; 495 } 496 497 498 /* 499 * read_capacity: 500 * Handle the read_capacity command. 501 * 502 * Parameter: argc, argv (shifted) 503 * 504 * Returns: 0 if OK - else it doesn't return at all. 505 */ 506 507 int 508 read_capacity(int argc, char **argv) 509 { 510 iscsi_iocommand_parameters_t io; 511 int rc; 512 uint32_t bsz; 513 uint64_t lbn, cap; 514 uint32_t n; 515 516 (void) memset(&io, 0x0, sizeof(io)); 517 if ((io.session_id = get_sessid(argc, argv, FALSE)) == 0) { 518 return 1; 519 } 520 io.lun = cl_get_longlong('l', argc, argv); 521 check_extra_args(argc, argv); 522 523 io.req.cmdlen = 10; 524 io.req.cmd[0] = 0x25; 525 526 io.req.datalen = 8; 527 528 if ((rc = do_ioctl(&io, TRUE)) != 0) { 529 return rc; 530 } 531 (void) memcpy(&n, buf, sizeof(n)); 532 lbn = (uint64_t)(n + 1); 533 (void) memcpy(&n, &buf[4], sizeof(n)); 534 bsz = ntohl(n); 535 cap = lbn * bsz; 536 printf("Total Blocks: %" PRIu64 ", Block Size: %u, Capacity: %" PRIu64 " Bytes\n", 537 lbn, bsz, cap); 538 539 return 0; 540 } 541 542 543 /* 544 * test_unit_ready: 545 * Handle the test_unit_ready command. 546 * 547 * Parameter: argc, argv (shifted) 548 * 549 * Returns: 0 if OK - else it doesn't return at all. 550 */ 551 552 int 553 test_unit_ready(int argc, char **argv) 554 { 555 iscsi_iocommand_parameters_t io; 556 int rc; 557 558 (void) memset(&io, 0x0, sizeof(io)); 559 if ((io.session_id = get_sessid(argc, argv, FALSE)) == 0) { 560 return 1; 561 } 562 io.lun = cl_get_longlong('l', argc, argv); 563 check_extra_args(argc, argv); 564 565 io.req.cmdlen = 6; 566 io.req.cmd[0] = 0x00; 567 568 io.req.datalen = 0; 569 570 if ((rc = do_ioctl(&io, TRUE)) != 0) { 571 return rc; 572 } 573 printf("Unit is ready\n"); 574 return 0; 575 } 576 577 578 /* 579 * report_luns: 580 * Handle the report_luns command. 581 * 582 * Parameter: argc, argv (shifted) 583 * 584 * Returns: 0 if OK - else it doesn't return at all. 585 */ 586 587 int 588 report_luns(int argc, char **argv) 589 { 590 iscsi_iocommand_parameters_t io; 591 int rc; 592 size_t llen; 593 uint32_t n; 594 uint64_t *lp; 595 596 (void) memset(&io, 0x0, sizeof(io)); 597 if ((io.session_id = get_sessid(argc, argv, FALSE)) == 0) { 598 return 1; 599 } 600 check_extra_args(argc, argv); 601 602 io.req.cmdlen = 12; 603 io.req.cmd[0] = 0xa0; 604 n = htonl(sizeof(buf)); 605 (void) memcpy(&io.req.cmd[6], &n, sizeof(n)); 606 607 io.req.datalen = sizeof(buf); 608 609 if ((rc = do_ioctl(&io, TRUE)) != 0) { 610 return rc; 611 } 612 (void) memcpy(&n, buf, sizeof(n)); 613 llen = ntohl(n); 614 if (!llen) { 615 printf("No LUNs!\n"); 616 return 1; 617 } 618 if (llen + 8 > sizeof(buf)) 619 printf("Partial "); 620 printf("LUN List:\n"); 621 lp = (uint64_t *)(void *) &buf[8]; 622 623 for (llen = min(llen, sizeof(buf) - 8) / 8; llen; llen--) { 624 printf(" 0x%" PRIx64 "\n", ntohq(*lp)); 625 lp++; 626 } 627 return 0; 628 } 629