1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2020 RackTop Systems, Inc.
25 */
26
27
28
29 #include <stdio.h>
30 #include <hbaapi.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <netinet/in.h>
34 #include <inttypes.h>
35 #include <ctype.h>
36 #include "fcinfo.h"
37
38 #ifdef _BIG_ENDIAN
39 #define htonll(x) (x)
40 #define ntohll(x) (x)
41 #else
42 #define htonll(x) ((((unsigned long long)htonl(x)) << 32) + htonl(x >> 32))
43 #define ntohll(x) ((((unsigned long long)ntohl(x)) << 32) + ntohl(x >> 32))
44 #endif
45
46 /* Fc4 Types Format */
47 #define FC4_TYPE_WORD_POS(x) ((uint_t)((uint_t)(x) >> 5))
48 #define FC4_TYPE_BIT_POS(x) ((uchar_t)(x) & 0x1F)
49
50 #define TYPE_IP_FC 0x05
51 #define TYPE_SCSI_FCP 0x08
52
53 static int fc4_map_is_set(uint32_t *map, uchar_t ulp_type);
54 static char *getPortType(HBA_PORTTYPE portType);
55 static char *getPortState(HBA_PORTSTATE portState);
56 static void printPortSpeed(HBA_PORTSPEED portSpeed);
57 static char *getDTypeString(uchar_t dType);
58
wwnConversion(uchar_t * wwn)59 uint64_t wwnConversion(uchar_t *wwn) {
60 uint64_t tmp;
61 memcpy(&tmp, wwn, sizeof (uint64_t));
62 return (ntohll(tmp));
63 }
64
65 static char *
getPortType(HBA_PORTTYPE portType)66 getPortType(HBA_PORTTYPE portType) {
67 switch (portType) {
68 case HBA_PORTTYPE_UNKNOWN:
69 return ("unknown");
70 case HBA_PORTTYPE_OTHER:
71 return ("other");
72 case HBA_PORTTYPE_NOTPRESENT:
73 return ("not present");
74 case HBA_PORTTYPE_NPORT:
75 return ("N-port");
76 case HBA_PORTTYPE_NLPORT:
77 return ("NL-port");
78 case HBA_PORTTYPE_FLPORT:
79 return ("FL-port");
80 case HBA_PORTTYPE_FPORT:
81 return ("F-port");
82 case HBA_PORTTYPE_LPORT:
83 return ("L-port");
84 case HBA_PORTTYPE_PTP:
85 return ("point-to-point");
86 default:
87 return ("unrecognized type");
88 }
89 }
90
91 static char *
getPortState(HBA_PORTSTATE portState)92 getPortState(HBA_PORTSTATE portState) {
93 switch (portState) {
94 case HBA_PORTSTATE_UNKNOWN:
95 return ("unknown");
96 case HBA_PORTSTATE_ONLINE:
97 return ("online");
98 case HBA_PORTSTATE_OFFLINE:
99 return ("offline");
100 case HBA_PORTSTATE_BYPASSED:
101 return ("bypassed");
102 case HBA_PORTSTATE_DIAGNOSTICS:
103 return ("diagnostics");
104 case HBA_PORTSTATE_LINKDOWN:
105 return ("link down");
106 case HBA_PORTSTATE_ERROR:
107 return ("error");
108 case HBA_PORTSTATE_LOOPBACK:
109 return ("loopback");
110 default:
111 return ("unrecognized state");
112 }
113 }
114
115 static void
printPortSpeed(HBA_PORTSPEED portSpeed)116 printPortSpeed(HBA_PORTSPEED portSpeed) {
117 int foundSpeed = 0;
118
119 if ((portSpeed & HBA_PORTSPEED_1GBIT) == HBA_PORTSPEED_1GBIT) {
120 fprintf(stdout, "1Gb ");
121 foundSpeed = 1;
122 }
123 if ((portSpeed & HBA_PORTSPEED_2GBIT) == HBA_PORTSPEED_2GBIT) {
124 fprintf(stdout, "2Gb ");
125 foundSpeed = 1;
126 }
127 if ((portSpeed & HBA_PORTSPEED_4GBIT) == HBA_PORTSPEED_4GBIT) {
128 fprintf(stdout, "4Gb ");
129 foundSpeed = 1;
130 }
131 if ((portSpeed & HBA_PORTSPEED_8GBIT) == HBA_PORTSPEED_8GBIT) {
132 fprintf(stdout, "8Gb ");
133 foundSpeed = 1;
134 }
135 if ((portSpeed & HBA_PORTSPEED_10GBIT) == HBA_PORTSPEED_10GBIT) {
136 fprintf(stdout, "10Gb ");
137 foundSpeed = 1;
138 }
139 if ((portSpeed & HBA_PORTSPEED_16GBIT) == HBA_PORTSPEED_16GBIT) {
140 fprintf(stdout, "16Gb ");
141 foundSpeed = 1;
142 }
143 if ((portSpeed & HBA_PORTSPEED_32GBIT) == HBA_PORTSPEED_32GBIT) {
144 fprintf(stdout, "32Gb ");
145 foundSpeed = 1;
146 }
147 if ((portSpeed & HBA_PORTSPEED_NOT_NEGOTIATED)
148 == HBA_PORTSPEED_NOT_NEGOTIATED) {
149 fprintf(stdout, "not established ");
150 foundSpeed = 1;
151 }
152 if (foundSpeed == 0) {
153 fprintf(stdout, "not established ");
154 }
155 }
156
157 void
printDiscoPortInfo(HBA_PORTATTRIBUTES * discoPort,int scsiTargetType)158 printDiscoPortInfo(HBA_PORTATTRIBUTES *discoPort, int scsiTargetType) {
159 int fc4_types = 0;
160
161 fprintf(stdout, gettext("Remote Port WWN: %016llx\n"),
162 wwnConversion(discoPort->PortWWN.wwn));
163 fprintf(stdout, gettext("\tActive FC4 Types: "));
164 if (fc4_map_is_set(
165 (uint32_t *)discoPort->PortActiveFc4Types.bits,
166 TYPE_SCSI_FCP)) {
167 fprintf(stdout, gettext("SCSI"));
168 fc4_types++;
169 }
170 if (fc4_map_is_set(
171 (uint32_t *)discoPort->PortActiveFc4Types.bits,
172 TYPE_IP_FC)) {
173 if (fc4_types != 0) {
174 fprintf(stdout, ",");
175 }
176 fprintf(stdout, gettext("IP"));
177 fc4_types++;
178 }
179 fprintf(stdout, "\n");
180
181 /* print out scsi target type information */
182 fprintf(stdout, gettext("\tSCSI Target: "));
183 if (scsiTargetType == SCSI_TARGET_TYPE_YES) {
184 fprintf(stdout, gettext("yes\n"));
185 } else if (scsiTargetType == SCSI_TARGET_TYPE_NO) {
186 fprintf(stdout, gettext("no\n"));
187 } else {
188 fprintf(stdout, gettext("unknown\n"));
189 }
190 fprintf(stdout, gettext("\tPort Symbolic Name: %s\n"),
191 discoPort->PortSymbolicName);
192 fprintf(stdout, gettext("\tNode WWN: %016llx\n"),
193 wwnConversion(discoPort->NodeWWN.wwn));
194 }
195
196 /*
197 * scan the bitmap array for the specifed ULP type. The bit map array
198 * is 32 bytes long
199 */
200 static int
fc4_map_is_set(uint32_t * map,uchar_t ulp_type)201 fc4_map_is_set(uint32_t *map, uchar_t ulp_type)
202 {
203
204 map += FC4_TYPE_WORD_POS(ulp_type) * 4;
205
206 if (ntohl((*(uint32_t *)map)) & (1 << FC4_TYPE_BIT_POS(ulp_type))) {
207 return (1);
208 }
209
210 return (0);
211 }
212
213 /*
214 * prints out all the HBA port information
215 */
216 void
printHBAPortInfo(HBA_PORTATTRIBUTES * port,HBA_ADAPTERATTRIBUTES * attrs,int mode)217 printHBAPortInfo(HBA_PORTATTRIBUTES *port,
218 HBA_ADAPTERATTRIBUTES *attrs, int mode) {
219 if (attrs == NULL || port == NULL) {
220 return;
221 }
222 fprintf(stdout, gettext("HBA Port WWN: %016llx\n"),
223 wwnConversion(port->PortWWN.wwn));
224 fprintf(stdout, gettext("\tPort Mode: %s\n"),
225 (mode == INITIATOR_MODE) ? "Initiator" : "Target");
226 fprintf(stdout, gettext("\tPort ID: %x\n"),
227 port->PortFcId);
228 fprintf(stdout, gettext("\tOS Device Name: %s\n"), port->OSDeviceName);
229
230 fprintf(stdout, gettext("\tManufacturer: %s\n"),
231 attrs->Manufacturer);
232 fprintf(stdout, gettext("\tModel: %s\n"), attrs->Model);
233 fprintf(stdout, gettext("\tFirmware Version: %s\n"),
234 attrs->FirmwareVersion);
235 fprintf(stdout, gettext("\tFCode/BIOS Version: %s\n"),
236 attrs->OptionROMVersion);
237 fprintf(stdout, gettext("\tSerial Number: %s\n"),
238 attrs->SerialNumber[0] == 0? "not available":attrs->SerialNumber);
239
240 fprintf(stdout, gettext("\tDriver Name: %s\n"),
241 attrs->DriverName[0] == 0? "not available":attrs->DriverName);
242 fprintf(stdout, gettext("\tDriver Version: %s\n"),
243 attrs->DriverVersion[0] == 0? "not available":attrs->DriverVersion);
244
245 fprintf(stdout, gettext("\tType: %s\n"),
246 getPortType(port->PortType));
247 fprintf(stdout, gettext("\tState: %s\n"),
248 getPortState(port->PortState));
249
250 fprintf(stdout, gettext("\tSupported Speeds: "));
251 printPortSpeed(port->PortSupportedSpeed);
252 fprintf(stdout, "\n");
253
254 fprintf(stdout, gettext("\tCurrent Speed: "));
255 printPortSpeed(port->PortSpeed);
256 fprintf(stdout, "\n");
257
258 fprintf(stdout, gettext("\tNode WWN: %016llx\n"),
259 wwnConversion(port->NodeWWN.wwn));
260 }
261
262 void
printStatus(HBA_STATUS status)263 printStatus(HBA_STATUS status) {
264 switch (status) {
265 case HBA_STATUS_OK:
266 fprintf(stderr, gettext("OK"));
267 return;
268 case HBA_STATUS_ERROR:
269 fprintf(stderr, gettext("ERROR"));
270 return;
271 case HBA_STATUS_ERROR_NOT_SUPPORTED:
272 fprintf(stderr, gettext("NOT SUPPORTED"));
273 return;
274 case HBA_STATUS_ERROR_INVALID_HANDLE:
275 fprintf(stderr, gettext("INVALID HANDLE"));
276 return;
277 case HBA_STATUS_ERROR_ARG:
278 fprintf(stderr, gettext("ERROR ARG"));
279 return;
280 case HBA_STATUS_ERROR_ILLEGAL_WWN:
281 fprintf(stderr, gettext("ILLEGAL WWN"));
282 return;
283 case HBA_STATUS_ERROR_ILLEGAL_INDEX:
284 fprintf(stderr, gettext("ILLEGAL INDEX"));
285 return;
286 case HBA_STATUS_ERROR_MORE_DATA:
287 fprintf(stderr, gettext("MORE DATA"));
288 return;
289 case HBA_STATUS_ERROR_STALE_DATA:
290 fprintf(stderr, gettext("STALE DATA"));
291 return;
292 case HBA_STATUS_SCSI_CHECK_CONDITION:
293 fprintf(stderr, gettext("SCSI CHECK CONDITION"));
294 return;
295 case HBA_STATUS_ERROR_BUSY:
296 fprintf(stderr, gettext("BUSY"));
297 return;
298 case HBA_STATUS_ERROR_TRY_AGAIN:
299 fprintf(stderr, gettext("TRY AGAIN"));
300 return;
301 case HBA_STATUS_ERROR_UNAVAILABLE:
302 fprintf(stderr, gettext("UNAVAILABLE"));
303 return;
304 default:
305 fprintf(stderr, "%s %d",
306 gettext("Undefined error code "), status);
307 return;
308 }
309 }
310
311 void
printLUNInfo(struct scsi_inquiry * inq,HBA_UINT32 scsiLUN,char * devpath)312 printLUNInfo(struct scsi_inquiry *inq, HBA_UINT32 scsiLUN, char *devpath) {
313 fprintf(stdout, "\tLUN: %d\n", scsiLUN);
314 fprintf(stdout, "\t Vendor: %c%c%c%c%c%c%c%c\n",
315 inq->inq_vid[0],
316 inq->inq_vid[1],
317 inq->inq_vid[2],
318 inq->inq_vid[3],
319 inq->inq_vid[4],
320 inq->inq_vid[5],
321 inq->inq_vid[6],
322 inq->inq_vid[7]);
323 fprintf(stdout, "\t Product: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
324 inq->inq_pid[0],
325 inq->inq_pid[1],
326 inq->inq_pid[2],
327 inq->inq_pid[3],
328 inq->inq_pid[4],
329 inq->inq_pid[5],
330 inq->inq_pid[6],
331 inq->inq_pid[7],
332 inq->inq_pid[8],
333 inq->inq_pid[9],
334 inq->inq_pid[10],
335 inq->inq_pid[11],
336 inq->inq_pid[12],
337 inq->inq_pid[13],
338 inq->inq_pid[14],
339 inq->inq_pid[15]);
340 fprintf(stdout, gettext("\t OS Device Name: %s\n"), devpath);
341 }
342
343 void
printPortStat(fc_rls_acc_t * rls_payload)344 printPortStat(fc_rls_acc_t *rls_payload) {
345 fprintf(stdout, gettext("\tLink Error Statistics:\n"));
346 fprintf(stdout, gettext("\t\tLink Failure Count: %u\n"),
347 rls_payload->rls_link_fail);
348 fprintf(stdout, gettext("\t\tLoss of Sync Count: %u\n"),
349 rls_payload->rls_sync_loss);
350 fprintf(stdout, gettext("\t\tLoss of Signal Count: %u\n"),
351 rls_payload->rls_sig_loss);
352 fprintf(stdout, gettext("\t\tPrimitive Seq Protocol Error Count: %u\n"),
353 rls_payload->rls_prim_seq_err);
354 fprintf(stdout, gettext("\t\tInvalid Tx Word Count: %u\n"),
355 rls_payload->rls_invalid_word);
356 fprintf(stdout, gettext("\t\tInvalid CRC Count: %u\n"),
357 rls_payload->rls_invalid_crc);
358 }
359
360 /*
361 * return device type description
362 *
363 * Arguments:
364 * dType - Device type returned from Standard INQUIRY
365 * Returns:
366 * char string description for device type
367 */
368 static char *
getDTypeString(uchar_t dType)369 getDTypeString(uchar_t dType)
370 {
371 switch (dType & DTYPE_MASK) {
372 case DTYPE_DIRECT:
373 return ("Disk Device");
374 case DTYPE_SEQUENTIAL:
375 return ("Tape Device");
376 case DTYPE_PRINTER:
377 return ("Printer Device");
378 case DTYPE_PROCESSOR:
379 return ("Processor Device");
380 case DTYPE_WORM:
381 return ("WORM Device");
382 case DTYPE_RODIRECT:
383 return ("CD/DVD Device");
384 case DTYPE_SCANNER:
385 return ("Scanner Device");
386 case DTYPE_OPTICAL:
387 return ("Optical Memory Device");
388 case DTYPE_CHANGER:
389 return ("Medium Changer Device");
390 case DTYPE_COMM:
391 return ("Communications Device");
392 case DTYPE_ARRAY_CTRL:
393 return ("Storage Array Controller Device");
394 case DTYPE_ESI:
395 return ("Enclosure Services Device");
396 case DTYPE_RBC:
397 return ("Simplified Direct-access Device");
398 case DTYPE_OCRW:
399 return ("Optical Card Reader/Writer Device");
400 case DTYPE_BCC:
401 return ("Bridge Controller Commands");
402 case DTYPE_OSD:
403 return ("Object-based Storage Device");
404 case DTYPE_ADC:
405 return ("Automation/Drive Interface");
406 case DTYPE_WELLKNOWN:
407 return ("Well Known Logical Unit");
408 case DTYPE_UNKNOWN:
409 return ("Unknown Device");
410 default:
411 return ("Undefined");
412 }
413 }
414
415 /*
416 * print the OS device name for the logical-unit object
417 *
418 * Arguments:
419 * devListWalk - OS device path info
420 * verbose - boolean indicating whether to display additional info
421 *
422 * returns:
423 * none
424 */
425 void
printOSDeviceNameInfo(discoveredDevice * devListWalk,boolean_t verbose)426 printOSDeviceNameInfo(discoveredDevice *devListWalk, boolean_t verbose)
427 {
428 portWWNList *WWNList;
429 tgtPortWWNList *tgtWWNList;
430 int i, count;
431
432 fprintf(stdout, "OS Device Name: %s\n", devListWalk->OSDeviceName);
433 if (verbose == B_TRUE) {
434 for (WWNList = devListWalk->HBAPortWWN;
435 WWNList != NULL; WWNList = WWNList->next) {
436 fprintf(stdout, "\tHBA Port WWN: ");
437 fprintf(stdout, "%016llx",
438 wwnConversion(WWNList->portWWN.wwn));
439 for (tgtWWNList = WWNList->tgtPortWWN;
440 tgtWWNList != NULL; tgtWWNList = tgtWWNList->next) {
441 fprintf(stdout, "\n\t\tRemote Port WWN: ");
442 fprintf(stdout, "%016llx",
443 wwnConversion(tgtWWNList->portWWN.wwn));
444 fprintf(stdout, "\n\t\t\tLUN: %d",
445 tgtWWNList->scsiOSLun);
446 }
447 fprintf(stdout, "\n");
448 }
449
450 fprintf(stdout, "\tVendor: ");
451 for (count = sizeof (devListWalk->VID), i = 0; i < count; i++) {
452 if (isprint(devListWalk->VID[i]))
453 fprintf(stdout, "%c", devListWalk->VID[i]);
454 }
455
456 fprintf(stdout, "\n\tProduct: ");
457 for (count = sizeof (devListWalk->PID), i = 0; i < count; i++) {
458 if (isprint(devListWalk->PID[i]))
459 fprintf(stdout, "%c", devListWalk->PID[i]);
460 }
461
462 fprintf(stdout, "\n\tDevice Type: %s\n",
463 getDTypeString(devListWalk->dType));
464 }
465 }
466