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
smartpqi_help(void)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 *
bool_to_str(int v)67 bool_to_str(int v)
68 {
69 return (v ? "TRUE" : "FALSE");
70 }
71
72 const mdb_modinfo_t *
_mdb_init(void)73 _mdb_init(void)
74 {
75 return (&modinfo);
76 }
77
78 static void
display_sense_data(struct scsi_extended_sense data)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
display_scsi_status(struct scsi_arq_status scsi_status)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 *
cmd_action_str(pqi_cmd_action_t action,char * tmpstr,int tmplen)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 *
mdb_cdb_to_str(uint8_t scsi_cmd,char * tmpstr,int tmplen)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
display_cdb(uint8_t * cdb)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 *
pqi_iu_type_to_str(int val)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
display_raid_error_info(uintptr_t error_info)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
display_io_request(pqi_io_request_t * io)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
display_cmd(pqi_cmd_t * cmdp)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 *
pqi_list_next(list_node_t * listp,size_t sz,void * structp,list_node_t * current)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
pqi_list_head(list_t list,uint8_t * drvp,size_t offset,list_node_t ** list_anchor)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
pqi_device_list_head(list_t s_devnodes,uint8_t * addr,list_node_t ** dev_head,struct pqi_device * dev)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
pqi_cmd_list_head(list_t cmds,uint8_t * addr,list_node_t ** cmd_head,struct pqi_cmd * cmdp)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 *
pqi_get_guid(char * pd_guid)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
display_device_info(pqi_device_t * dev)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
pqi_display_devices(list_t s_devnodes,pqi_state_t * drvp,uint_t dev_verbose)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
pqi_display_instance(pqi_state_t * pqi_statep)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
pqi_getopts(uintptr_t addr,int argc,const mdb_arg_t * argv,uintptr_t * cntlr,uint_t * print_devices)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
smartpqi(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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