1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2023 Nexenta by DDN, Inc. All rights reserved. 14 */ 15 16 #include <sys/kmem.h> 17 #include <sys/proc.h> 18 #include <sys/time.h> 19 #include <sys/conf.h> 20 #include <sys/file.h> 21 #include <sys/ddi.h> 22 #include <sys/ddi_impldefs.h> 23 #include <sys/modctl.h> 24 #include <sys/sunddi.h> 25 #include <sys/scsi/scsi.h> 26 #include <sys/scsi/impl/scsi_reset_notify.h> 27 #include <sys/sunmdi.h> 28 #include <sys/mdi_impldefs.h> 29 30 #include <smartpqi.h> 31 #include <smartpqi_hw.h> 32 33 #include <sys/scsi/scsi_types.h> 34 #include <sys/disp.h> 35 #include <sys/types.h> 36 #include <sys/mdb_modapi.h> 37 38 #define INVALID_OPT_VAL ((uintptr_t)(-1)) 39 40 /* ---- Forward references ---- */ 41 static int smartpqi(uintptr_t, uint_t, int, const mdb_arg_t *); 42 static void smartpqi_help(void); 43 44 static const mdb_dcmd_t dcmds[] = { 45 { 46 "smartpqi", "-c <controller number> [-v]", 47 "display smartpqi state", 48 smartpqi, 49 smartpqi_help 50 }, 51 { NULL } 52 }; 53 54 static const mdb_modinfo_t modinfo = { 55 MDB_API_VERSION, dcmds, NULL 56 }; 57 58 static void smartpqi_help(void) 59 { 60 mdb_printf("%s", 61 "-c <cntlr> display the state for <cntlr> and the no." 62 " of devices attached.\n" 63 "-v provide detailed information about each device attached.\n"); 64 } 65 66 char * 67 bool_to_str(int v) 68 { 69 return (v ? "TRUE" : "FALSE"); 70 } 71 72 const mdb_modinfo_t * 73 _mdb_init(void) 74 { 75 return (&modinfo); 76 } 77 78 static void 79 display_sense_data(struct scsi_extended_sense data) 80 { 81 mdb_printf(" SCSI sense data es_key 0x%x ", data.es_key); 82 mdb_printf(" es_add_code 0x%x ", data.es_add_code); 83 mdb_printf(" es_qual_code 0x%x\n", data.es_qual_code); 84 } 85 86 static void 87 display_scsi_status(struct scsi_arq_status scsi_status) 88 { 89 mdb_printf(" req pkt status\t\t\t0x%x\n", 90 *(int8_t *)&scsi_status.sts_rqpkt_status); 91 mdb_printf(" req pkt resid\t\t\t0x%x\n", 92 scsi_status.sts_rqpkt_resid); 93 mdb_printf(" req pkt state\t\t\t%d\n", scsi_status.sts_rqpkt_state); 94 mdb_printf(" req pkt state\t\t\t%d\n", 95 scsi_status.sts_rqpkt_statistics); 96 if (scsi_status.sts_status.sts_chk) 97 display_sense_data(scsi_status.sts_sensedata); 98 } 99 100 static char * 101 cmd_action_str(pqi_cmd_action_t action, char *tmpstr, int tmplen) 102 { 103 switch (action) { 104 case PQI_CMD_UNINIT: 105 return ("UNINIT"); 106 case PQI_CMD_QUEUE: 107 return ("QUEUE"); 108 case PQI_CMD_START: 109 return ("START"); 110 case PQI_CMD_CMPLT: 111 return ("COMPLETE"); 112 case PQI_CMD_TIMEOUT: 113 return ("TIMEOUT"); 114 case PQI_CMD_FAIL: 115 return ("FAIL"); 116 default: 117 (void) mdb_snprintf(tmpstr, tmplen, "BAD ACTION <0x%x>", 118 action); 119 return (tmpstr); 120 } 121 } 122 123 struct scsi_key_strings pqi_cmds[] = { 124 SCSI_CMDS_KEY_STRINGS, 125 BMIC_READ, "BMIC Read", 126 BMIC_WRITE, "BMIC Write", 127 CISS_REPORT_LOG, "CISS Report Logical", 128 CISS_REPORT_PHYS, "CISS Report Physical", 129 -1, NULL 130 }; 131 132 static char * 133 mdb_cdb_to_str(uint8_t scsi_cmd, char *tmpstr, int tmplen) 134 { 135 int i = 0; 136 137 while (pqi_cmds[i].key != -1) { 138 if (scsi_cmd == pqi_cmds[i].key) 139 return ((char *)pqi_cmds[i].message); 140 i++; 141 } 142 (void) mdb_snprintf(tmpstr, tmplen, "<undecoded cmd 0x%x>", scsi_cmd); 143 return (tmpstr); 144 } 145 146 static void 147 display_cdb(uint8_t *cdb) 148 { 149 int i, tmplen; 150 char tmpstr[64]; 151 152 tmplen = sizeof (tmpstr); 153 mdb_printf("CDB %s", mdb_cdb_to_str(cdb[0], tmpstr, tmplen)); 154 for (i = 1; i < SCSI_CDB_SIZE; i++) 155 mdb_printf(":%02x", cdb[i]); 156 157 mdb_printf("\n"); 158 } 159 160 static char * 161 pqi_iu_type_to_str(int val) 162 { 163 switch (val) { 164 case PQI_RESPONSE_IU_RAID_PATH_IO_SUCCESS: return ("Success"); 165 case PQI_RESPONSE_IU_AIO_PATH_IO_SUCCESS: return ("AIO Success"); 166 case PQI_RESPONSE_IU_GENERAL_MANAGEMENT: return ("General"); 167 case PQI_RESPONSE_IU_TASK_MANAGEMENT: return ("Task"); 168 case PQI_RESPONSE_IU_RAID_PATH_IO_ERROR: return ("IO Error"); 169 case PQI_RESPONSE_IU_AIO_PATH_IO_ERROR: return ("AIO IO Error"); 170 case PQI_RESPONSE_IU_AIO_PATH_DISABLED: return ("AIO Path Disabled"); 171 default: return ("UNHANDLED"); 172 } 173 } 174 175 static void 176 display_raid_error_info(uintptr_t error_info) 177 { 178 struct pqi_raid_error_info info; 179 int cnt; 180 181 if (error_info == 0) 182 return; 183 if ((cnt = mdb_vread((void *)&info, sizeof (struct pqi_raid_error_info), 184 (uintptr_t)error_info)) != 185 sizeof (struct pqi_raid_error_info)) { 186 mdb_warn(" Unable to read Raid error info(%d,%p)\n", 187 cnt, error_info); 188 return; 189 } 190 191 mdb_printf(" ---- Raid error info ----\n"); 192 mdb_printf(" data_in_result %d\n", info.data_in_result); 193 mdb_printf(" data_out_result %d\n", info.data_out_result); 194 mdb_printf(" status %d\n", info.status); 195 mdb_printf(" status_qualifier %d\n", info.status_qualifier); 196 mdb_printf(" sense_data_length %d\n", info.sense_data_length); 197 mdb_printf(" response_data_length %d\n", info.response_data_length); 198 mdb_printf(" data_in_transferred %d\n", info.data_in_transferred); 199 mdb_printf(" data_out_transferred %d\n", info.data_out_transferred); 200 } 201 202 static void 203 display_io_request(pqi_io_request_t *io) 204 { 205 if (io == (pqi_io_request_t *)0) 206 return; 207 208 mdb_printf(" ---- Command IO request ----\n"); 209 mdb_printf(" io_refcount\t\t\t\t%d\n", io->io_refcount); 210 mdb_printf(" io_index\t\t\t\t%d\n", io->io_index); 211 mdb_printf(" io_gen\t\t\t\t%d\n", io->io_gen); 212 mdb_printf(" io_serviced\t\t\t\t%s\n", bool_to_str(io->io_serviced)); 213 mdb_printf(" io_raid_bypass\t\t\t%d\n", io->io_raid_bypass); 214 mdb_printf(" io_status\t\t\t\t%d\n", io->io_status); 215 mdb_printf(" io_iu\t\t\t\t0x%p\n", io->io_iu); 216 mdb_printf(" io_pi\t\t\t\t%d\n", io->io_pi); 217 mdb_printf(" io_iu_type\t\t\t\t%s\n", 218 pqi_iu_type_to_str(io->io_iu_type)); 219 display_raid_error_info((uintptr_t)io->io_error_info); 220 } 221 222 static int 223 display_cmd(pqi_cmd_t *cmdp) 224 { 225 int read_cnt, tmplen; 226 char tmpstr[64]; 227 pqi_io_request_t pqi_io; 228 229 tmplen = sizeof (tmpstr); 230 display_cdb(cmdp->pc_cdb); 231 mdb_printf(" cur action\t\t\t%s\n", 232 cmd_action_str(cmdp->pc_cur_action, tmpstr, tmplen)); 233 mdb_printf(" last action\t\t\t%s\n", 234 cmd_action_str(cmdp->pc_last_action, tmpstr, tmplen)); 235 display_scsi_status(cmdp->pc_cmd_scb); 236 mdb_printf(" pc_dma_count\t\t\t%d\n", cmdp->pc_dma_count); 237 mdb_printf(" pc_flags\t\t\t\t0x%x\n", cmdp->pc_flags); 238 mdb_printf(" pc_statuslen\t\t\t%d\n", cmdp->pc_statuslen); 239 mdb_printf(" pc_cmdlen\t\t\t\t%d\n", cmdp->pc_cmdlen); 240 241 if (cmdp->pc_io_rqst == (pqi_io_request_t *)0) 242 return (DCMD_OK); 243 244 read_cnt = mdb_vread(&pqi_io, sizeof (pqi_io_request_t), 245 (uintptr_t)cmdp->pc_io_rqst); 246 if (read_cnt == -1) { 247 mdb_warn(" Error reading IO structure address 0x%p - " 248 "skipping diplay of IO commands\n", 249 cmdp->pc_io_rqst); 250 return (DCMD_ERR); 251 } else if (read_cnt != sizeof (pqi_io_request_t)) { 252 mdb_warn(" cannot read IO structure count %d at0x%p - " 253 "skipping diplay of IO commands\n", 254 read_cnt, cmdp->pc_io_rqst); 255 return (DCMD_ERR); 256 } else { 257 display_io_request(&pqi_io); 258 } 259 return (DCMD_OK); 260 } 261 262 /* 263 * listp - the pointer to the head of the linked list 264 * sz - size of the lest element to be read 265 * current - pointer to current list_node structure in local storage 266 */ 267 static list_node_t * 268 pqi_list_next(list_node_t *listp, size_t sz, void *structp, 269 list_node_t *current) 270 { 271 int rval; 272 273 if (current->list_next == (list_node_t *)listp) 274 return ((list_node_t *)NULL); 275 276 if (current->list_next == (list_node_t *)NULL) 277 return ((list_node_t *)NULL); 278 279 if (current->list_next == current->list_prev) 280 return ((list_node_t *)NULL); 281 282 rval = mdb_vread(structp, sz, (uintptr_t)current->list_next); 283 if (rval == -1 || (size_t)rval != sz) { 284 mdb_warn("Error reading a next list element so " 285 "skipping display of remaining elements\n"); 286 return ((list_node_t *)NULL); 287 } 288 return (current); 289 } 290 291 static void 292 pqi_list_head(list_t list, uint8_t *drvp, size_t offset, 293 list_node_t **list_anchor) 294 { 295 *list_anchor = (list_node_t *)(drvp + 296 offset + offsetof(list_t, list_head)); 297 if (*list_anchor == list.list_head.list_next) { 298 *list_anchor = NULL; 299 } 300 } 301 302 static int 303 pqi_device_list_head(list_t s_devnodes, uint8_t *addr, 304 list_node_t **dev_head, struct pqi_device *dev) 305 { 306 int rval; 307 308 pqi_list_head(s_devnodes, addr, offsetof(struct pqi_state, s_devnodes), 309 dev_head); 310 if (*dev_head == NULL) 311 return (DCMD_ERR); 312 313 rval = mdb_vread((void *)dev, sizeof (struct pqi_device), 314 (uintptr_t)s_devnodes.list_head.list_next); 315 if (rval == -1) { 316 mdb_warn(" cannot read device list head (0x%p)\n", 317 *dev_head); 318 return (DCMD_ERR); 319 } 320 return (DCMD_OK); 321 } 322 323 static int 324 pqi_cmd_list_head(list_t cmds, uint8_t *addr, 325 list_node_t **cmd_head, struct pqi_cmd *cmdp) 326 { 327 int rval; 328 329 pqi_list_head(cmds, (uint8_t *)addr, 330 offsetof(struct pqi_device, pd_cmd_list), 331 cmd_head); 332 /* Read in the first entry of the command list */ 333 rval = mdb_vread(cmdp, sizeof (struct pqi_cmd), 334 (uintptr_t)cmds.list_head.list_next); 335 if (rval == -1) { 336 mdb_warn(" cannot read initial entry in " 337 "command list (0x%p)\n", cmds.list_head.list_next); 338 } 339 return (rval); 340 } 341 342 static char * 343 pqi_get_guid(char *pd_guid) 344 { 345 static char myguid[41]; 346 347 if (mdb_vread(myguid, sizeof (myguid) - 1, (uintptr_t)pd_guid) == -1) 348 myguid[0] = '\0'; 349 350 return (myguid); 351 } 352 353 static void 354 display_device_info(pqi_device_t *dev) 355 { 356 char str[40]; 357 358 mdb_printf("-- Device pd_target %d --\n", dev->pd_target); 359 360 mdb_printf("pd_devtype\t\t\t\t%d\n", dev->pd_devtype); 361 mdb_printf("device pd_flags\t\t\t\t0x%x\n", dev->pd_flags); 362 mdb_printf("pd_active_cmds\t\t\t\t%d\n", dev->pd_active_cmds); 363 364 mdb_printf("pd_dip\t\t\t\t\t0x%p\n", dev->pd_dip); 365 mdb_printf("pd_pip\t\t\t\t\t0x%p\n", dev->pd_pip); 366 mdb_printf("pd_pip_offlined\t\t\t\t0x%p\n", dev->pd_pip_offlined); 367 368 mdb_printf("pd_online\t\t\t\t%s\n", bool_to_str(dev->pd_online)); 369 mdb_printf("pd_scanned\t\t\t\t%s\n", bool_to_str(dev->pd_scanned)); 370 mdb_printf("pd_phys_dev\t\t\t\t%s\n", bool_to_str(dev->pd_phys_dev)); 371 mdb_printf("pd_external_raid\t\t\t%s\n", 372 bool_to_str(dev->pd_external_raid)); 373 mdb_printf("pd_pd_aio_enabled\t\t\t%s\n", 374 bool_to_str(dev->pd_aio_enabled)); 375 376 mdb_printf("GUID\t\t\t\t\t%s\n", pqi_get_guid(dev->pd_guid)); 377 378 (void) strncpy(str, (char *)(dev->pd_vendor), sizeof (dev->pd_vendor)); 379 str[sizeof (dev->pd_vendor)] = '\0'; 380 mdb_printf("pd_vendor\t\t\t\t%s\n", str); 381 (void) strncpy(str, (char *)(dev->pd_model), sizeof (dev->pd_model)); 382 str[sizeof (dev->pd_model)] = '\0'; 383 mdb_printf("pd_model\t\t\t\t%s\n", str); 384 } 385 386 /* 387 * display device info: number of drives attached, number of commands running on 388 * each device, drive data and command data. 389 */ 390 static void 391 pqi_display_devices(list_t s_devnodes, pqi_state_t *drvp, uint_t dev_verbose) 392 { 393 int rval; 394 int dev_count = 0; 395 struct pqi_device d; 396 pqi_device_t *next_dp; 397 pqi_cmd_t *cmdp; 398 399 struct list_node *list_head; 400 struct list_node *d_list_head; 401 struct list_node *dev_current; 402 struct list_node *cmd_current; 403 struct pqi_device *d_drvrp; /* driver addr of device list entry */ 404 405 mdb_printf("---- Devices for controller (0x%p) ----\n", 406 ((uint8_t *)drvp) + 407 offsetof(struct pqi_state, s_devnodes)); 408 409 rval = pqi_device_list_head(s_devnodes, 410 (uint8_t *)drvp, &d_list_head, &d); 411 if (d_list_head == NULL) { 412 mdb_printf("Number of devices %d\n", dev_count); 413 return; 414 } 415 cmdp = (pqi_cmd_t *)mdb_alloc(sizeof (struct pqi_cmd), UM_SLEEP|UM_GC); 416 417 next_dp = &d; 418 419 dev_current = (list_node_t *)((uint8_t *)(&d) + 420 offsetof(struct pqi_device, pd_list)); 421 d_drvrp = (pqi_device_t *)(s_devnodes.list_head.list_next); 422 while (dev_current != NULL) { 423 if (dev_verbose) { 424 display_device_info((pqi_device_t *)&d); 425 426 /* now display command information */ 427 rval = pqi_cmd_list_head(d.pd_cmd_list, 428 (uint8_t *)d_drvrp, &list_head, cmdp); 429 if (rval == -1) { 430 mdb_warn("unable to read the command list head" 431 " for device %d\n", d.pd_target); 432 list_head = NULL; 433 } 434 if (list_head != NULL) { 435 mdb_printf(" ---- Commands for device %d" 436 " (0x%p) ----\n", 437 next_dp->pd_target, list_head); 438 439 cmd_current = 440 (list_node_t *)((uint8_t *)(cmdp) + 441 offsetof(struct pqi_cmd, pc_list)); 442 443 while (cmd_current != NULL) { 444 rval = display_cmd(cmdp); 445 if (rval != DCMD_OK) { 446 mdb_warn("Display of commands" 447 " aborted (%d)\n", 448 rval); 449 break; 450 } 451 452 cmd_current = pqi_list_next(list_head, 453 sizeof (struct pqi_cmd), 454 (void *)cmdp, cmd_current); 455 } 456 } 457 } 458 d_drvrp = (pqi_device_t *)(next_dp->pd_list.list_next); 459 dev_current = pqi_list_next( 460 d_list_head, 461 sizeof (struct pqi_device), 462 (void*)next_dp, 463 dev_current); 464 dev_count++; 465 } 466 467 if (!dev_verbose) 468 mdb_printf("Number of devices\t\t\t%d\n", dev_count); 469 } 470 471 static void 472 pqi_display_instance(pqi_state_t *pqi_statep) 473 { 474 mdb_printf("s_dip\t\t\t\t\t0x%p\n", pqi_statep->s_dip); 475 mdb_printf("s_flags\t\t\t\t\t0x%x\n", pqi_statep->s_flags); 476 mdb_printf("s_firmware_version\t\t\t%s\n", 477 pqi_statep->s_firmware_version); 478 479 mdb_printf("s_offline\t\t\t\t%s\ns_disable_mpxio\t\t\t\t%s\n", 480 bool_to_str(pqi_statep->s_offline), 481 bool_to_str(pqi_statep->s_disable_mpxio)); 482 mdb_printf("s_debug level\t\t\t\t%d\n", pqi_statep->s_debug_level); 483 484 mdb_printf("---- State for watchdog----\n"); 485 mdb_printf("s_intr_count\t\t\t\t%d\n", pqi_statep->s_intr_count); 486 mdb_printf("s_last_intr_count\t\t\t%d\n", 487 pqi_statep->s_last_intr_count); 488 mdb_printf("s_last_heartbeat_count\t\t\t%d\n", 489 pqi_statep->s_last_heartbeat_count); 490 491 mdb_printf("---- PQI cpabilities from controller ----\n"); 492 mdb_printf("s_max_inbound_queues\t\t\t%d\n", 493 pqi_statep->s_max_inbound_queues); 494 mdb_printf("s_max_elements_per_iq\t\t\t%d\n", 495 pqi_statep->s_max_elements_per_iq); 496 mdb_printf("s_max_iq_element_length\t\t\t%d\n", 497 pqi_statep->s_max_iq_element_length); 498 mdb_printf("s_max_outbound_queues\t\t\t%d\n", 499 pqi_statep->s_max_outbound_queues); 500 mdb_printf("s_max_elements_per_oq\t\t\t%d\n", 501 pqi_statep->s_max_elements_per_oq); 502 mdb_printf("s_max_elements_per_oq\t\t\t%d\n", 503 pqi_statep->s_max_elements_per_oq); 504 mdb_printf("s_max_oq_element_length\t\t\t%d\n", 505 pqi_statep->s_max_oq_element_length); 506 mdb_printf("s_max_inbound_iu_length_per_firmware\t%d\n", 507 pqi_statep->s_max_inbound_iu_length_per_firmware); 508 mdb_printf("s_max_inbound_queues\t\t\t%d\n", 509 pqi_statep->s_max_inbound_queues); 510 mdb_printf("s_inbound_spanning_supported:\t\t%d\n", 511 pqi_statep->s_inbound_spanning_supported); 512 mdb_printf("s_outbound_spanning_supported:\t\t%dk\n", 513 pqi_statep->s_outbound_spanning_supported); 514 mdb_printf("s_outbound_spanning_supported:\t\t%d\n", 515 pqi_statep->s_outbound_spanning_supported); 516 mdb_printf("s_pqi_mode_enabled:\t\t\t%d\n", 517 pqi_statep->s_pqi_mode_enabled); 518 mdb_printf("s_cmd_queue_len\t\t\t\t%d\n", pqi_statep->s_cmd_queue_len); 519 520 mdb_printf("---- SIS capabilities from controller ----\n"); 521 mdb_printf("s_max_sg_entries\t\t\t%d\n", pqi_statep->s_max_sg_entries); 522 mdb_printf("s_max_xfer_size\t\t\t\t%d\n", pqi_statep->s_max_xfer_size); 523 mdb_printf("s_max_outstainding_requests\t\t%d\n", 524 pqi_statep->s_max_sg_entries); 525 526 mdb_printf("---- Computed values from config ----\n"); 527 mdb_printf("s_max_sg_per_iu\t\t\t\t%d\n", pqi_statep->s_max_sg_per_iu); 528 mdb_printf("s_num_elements_per_iq\t\t\t%d\n", 529 pqi_statep->s_num_elements_per_iq); 530 mdb_printf("s_num_elements_per_oq\t\t\t%d\n", 531 pqi_statep->s_num_elements_per_oq); 532 mdb_printf("s_max_inbound_iu_length\t\t\t%d\n", 533 pqi_statep->s_max_inbound_iu_length); 534 mdb_printf("s_num_queue_groups\t\t\t%d\n", 535 pqi_statep->s_num_queue_groups); 536 mdb_printf("s_max_io_slots\t\t\t\t%d\n", pqi_statep->s_max_io_slots); 537 mdb_printf("s_sg_chain_buf_length\t\t\t%d\n", 538 pqi_statep->s_sg_chain_buf_length); 539 mdb_printf("s_max_sectors\t\t\t\t%d\n", pqi_statep->s_max_sectors); 540 541 mdb_printf("---- IO slot information ----\n"); 542 mdb_printf("s_io_rqst_pool\t\t\t\t0x%p\n", pqi_statep->s_io_rqst_pool); 543 mdb_printf("s_io_wait_cnt\t\t\t\t%d\n", pqi_statep->s_io_wait_cnt); 544 mdb_printf("s_next_io_slot\t\t\t\t%d\n", pqi_statep->s_next_io_slot); 545 mdb_printf("s_io_need\t\t\t\t%d\n", pqi_statep->s_io_need); 546 mdb_printf("s_io_had2wait\t\t\t\t%d\n", pqi_statep->s_io_had2wait); 547 mdb_printf("s_io_sig\t\t\t\t%d\n", pqi_statep->s_io_sig); 548 } 549 550 static int 551 pqi_getopts(uintptr_t addr, int argc, const mdb_arg_t *argv, uintptr_t *cntlr, 552 uint_t *print_devices) 553 { 554 uintptr_t device = INVALID_OPT_VAL; 555 556 *cntlr = INVALID_OPT_VAL; 557 *print_devices = FALSE; 558 mdb_getopts(argc, argv, 559 'v', MDB_OPT_SETBITS, TRUE, print_devices, 560 'c', MDB_OPT_UINTPTR, (uintptr_t)cntlr, 561 'd', MDB_OPT_UINTPTR, (uintptr_t)&device, 562 NULL); 563 564 if (*cntlr == INVALID_OPT_VAL) { 565 mdb_warn("-c <controller> required\n"); 566 return (DCMD_USAGE); 567 } 568 569 return (DCMD_OK); 570 } 571 572 static int 573 smartpqi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 574 { 575 int array_size; 576 int rval; 577 int pqi_statesz = sizeof (struct pqi_state); 578 uintptr_t instance = INVALID_OPT_VAL; 579 uintptr_t adr; 580 void **array_vaddr; 581 void **pqi_array; 582 pqi_state_t *pqi_drvp; 583 struct i_ddi_soft_state ss; 584 pqi_state_t *pqi_statep; 585 uint_t print_devices = 0; 586 587 if ((flags & DCMD_ADDRSPEC) == 0) { 588 /* 589 * MDB has this peculiarity that addr can be non-null 590 * from a previous invocation: 591 * e.g. 0xfffffef49cd64000::smartpqi, 592 * but flags shows that 593 * the command line is ::spamrtpqi or ::smartpai <options> 594 * To make sure the desired command line options are 595 * honored, we set addr to 0 and proceed with evaluating 596 * these command as entered. 597 */ 598 addr = (uintptr_t)0; 599 } 600 rval = pqi_getopts(addr, argc, argv, &instance, &print_devices); 601 if (rval != DCMD_OK) { 602 return (rval); 603 } 604 605 /* read the address of the pqi_state variable in the smartpqi driver */ 606 if (mdb_readvar((void *)&adr, "pqi_state") == -1) { 607 mdb_warn("Cannot read pqi driver variable pqi_softstate.\n"); 608 return (DCMD_ERR); 609 } 610 /* now read the i_ddi_soft_state structure pointer */ 611 if (mdb_vread((void *)&ss, sizeof (ss), adr) != sizeof (ss)) { 612 mdb_warn("Cannot read smartpqi softstate struct" 613 " pqi_state (Invalid pointer?(0x%p)).\n", 614 (uintptr_t)adr); 615 return (DCMD_ERR); 616 } 617 /* 618 * now allocate space for the array containing the pqi_state 619 * pointers and read in this array 620 */ 621 array_size = ss.n_items * (sizeof (void*)); 622 array_vaddr = ss.array; 623 pqi_array = (void **)mdb_alloc(array_size, UM_SLEEP|UM_GC); 624 if (mdb_vread(pqi_array, array_size, (uintptr_t)array_vaddr) != 625 array_size) { 626 mdb_warn("Corrupted softstate struct\n"); 627 return (DCMD_ERR); 628 } 629 630 if (instance >= ss.n_items || pqi_array[instance] == NULL) { 631 mdb_warn("smartpqi - no information available for %d\n", 632 instance); 633 return (DCMD_USAGE); 634 } 635 636 pqi_statep = mdb_alloc(sizeof (struct pqi_state), UM_SLEEP|UM_GC); 637 adr = (uintptr_t)pqi_array[instance]; 638 639 pqi_drvp = (pqi_state_t *)adr; 640 if (mdb_vread(pqi_statep, pqi_statesz, adr) != pqi_statesz) { 641 mdb_warn("Cannot read pqi_state. adr 0x%p, size %d\n", 642 adr, pqi_statesz); 643 return (DCMD_ERR); 644 } 645 mdb_printf("-------- Controller %d pqi_state (0x%p) --------\n", 646 instance, adr); 647 pqi_display_instance(pqi_statep); 648 649 pqi_display_devices(pqi_statep->s_devnodes, pqi_drvp, print_devices); 650 651 return (DCMD_OK); 652 } 653