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