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 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <ctype.h>
27#include <printAttrs.h>
28
29static SAS_STATE hbastatus_string[] = {
30	HBA_STATUS_OK,				"Okay",
31	HBA_STATUS_ERROR,			"Error",
32	HBA_STATUS_ERROR_NOT_SUPPORTED,		"Not Supported",
33	HBA_STATUS_ERROR_INVALID_HANDLE,	"Invalid Handle",
34	HBA_STATUS_ERROR_ARG,			"Argument Error",
35	HBA_STATUS_ERROR_ILLEGAL_WWN,		"Illegal WWN",
36	HBA_STATUS_ERROR_ILLEGAL_INDEX,		"Illegal Index",
37	HBA_STATUS_ERROR_MORE_DATA,		"Not Enough Buffer for Data",
38	HBA_STATUS_ERROR_STALE_DATA,		"Stale Data",
39	HBA_STATUS_SCSI_CHECK_CONDITION,	"SCSI Check Condition",
40	HBA_STATUS_ERROR_BUSY,			"Busy",
41	HBA_STATUS_ERROR_TRY_AGAIN,		"Try Again",
42	HBA_STATUS_ERROR_UNAVAILABLE,		"Unavailable",
43	HBA_STATUS_ERROR_ELS_REJECT,		"ELS Reject",
44	HBA_STATUS_ERROR_INVALID_LUN,		"Invalid LUN",
45	HBA_STATUS_ERROR_INCOMPATIBLE,		"Request Incompatible",
46	HBA_STATUS_ERROR_AMBIGUOUS_WWN,		"Ambiguous WWN",
47	HBA_STATUS_ERROR_LOCAL_BUS,		"Local Bus Error",
48	HBA_STATUS_ERROR_LOCAL_TARGET,		"Local Target Error",
49	HBA_STATUS_ERROR_LOCAL_LUN,		"Local LUN Error",
50	HBA_STATUS_ERROR_LOCAL_SCSIID_BOUND,	"Local SCSIID Bound",
51	HBA_STATUS_ERROR_TARGET_FCID,		"Target FCID Error",
52	HBA_STATUS_ERROR_TARGET_NODE_WWN,	"Target Node WWN Error",
53	HBA_STATUS_ERROR_TARGET_PORT_WWN,	"Target Port WWN Error",
54	HBA_STATUS_ERROR_TARGET_LUN,		"Target LUN Error",
55	HBA_STATUS_ERROR_TARGET_LUID,		"Target LUID Error",
56	HBA_STATUS_ERROR_NO_SUCH_BINDING,	"No Such Binding",
57	HBA_STATUS_ERROR_NOT_A_TARGET,		"Not a Target",
58	HBA_STATUS_ERROR_UNSUPPORTED_FC4,	"Unsupported FC4",
59	HBA_STATUS_ERROR_INCAPABLE,		"Incapable",
60	HBA_STATUS_ERROR_TARGET_BUSY,		"Target Busy",
61	HBA_STATUS_ERROR_NOT_LOADED,		"Not Loaded",
62	HBA_STATUS_ERROR_ALREADY_LOADED,	"Alreday Loaded",
63	HBA_STATUS_ERROR_ILLEGAL_FCID,		"Illegal FCID",
64	HBA_STATUS_ERROR_NOT_ASCSIDEVICE,	"Not a SCSI Device",
65	HBA_STATUS_ERROR_INVALID_PROTOCOL_TYPE,	"Invalid Protocol Type",
66	HBA_STATUS_ERROR_BAD_EVENT_TYPE,	"Bad Event Type",
67	-1,					NULL
68};
69
70SAS_STATE porttype_string[] = {
71	HBA_PORTTYPE_UNKNOWN,		"UNKNOWN",
72	HBA_PORTTYPE_OTHER,		"OTHER",
73	HBA_PORTTYPE_NOTPRESENT,	"NOT Present",
74	HBA_PORTTYPE_SASDEVICE,		"SAS Device",
75	HBA_PORTTYPE_SATADEVICE,	"SATA Device",
76	HBA_PORTTYPE_SASEXPANDER, 	"SAS Expander",
77	-1,				NULL,
78};
79
80SAS_STATE portstate_string[] = {
81	HBA_PORTSTATE_UNKNOWN,		"unknown",
82	HBA_PORTSTATE_ONLINE,		"online",
83	HBA_PORTSTATE_OFFLINE,		"offline",
84	HBA_PORTSTATE_BYPASSED,		"bypassed",
85	HBA_PORTSTATE_DIAGNOSTICS,	"diagnostics",
86	HBA_PORTSTATE_LINKDOWN,		"link Down",
87	HBA_PORTSTATE_ERROR,		"port Error",
88	HBA_PORTSTATE_LOOPBACK,		"loopback",
89	HBA_PORTSTATE_DEGRADED,		"degraded",
90	-1,				NULL,
91};
92
93static SAS_STATE phystate_string[] = {
94	HBA_SASSTATE_UNKNOWN,		"unknown",
95	HBA_SASSTATE_DISABLED,		"disabled",
96	HBA_SASSTATE_FAILED,		"failed",
97	HBA_SASSTATE_SATASPINUP,	"sata-spinup",
98	HBA_SASSTATE_SATAPORTSEL,	"sata-portselector",
99	HBA_SASSPEED_1_5GBIT,		"1.5Gbit",
100	HBA_SASSPEED_3GBIT,		"3Gbit",
101	HBA_SASSPEED_6GBIT,		"6Gbit",
102	HBA_SASSPEED_12GBIT,		"12Gbit",
103	-1,				NULL,
104};
105
106static SAS_STATE dtype_string[] = {
107	DTYPE_DIRECT,			"Disk Device",
108	DTYPE_SEQUENTIAL,		"Tape Device",
109	DTYPE_PRINTER,			"Printer Device",
110	DTYPE_PROCESSOR,		"Processor Device",
111	DTYPE_WORM,			"WORM Device",
112	DTYPE_RODIRECT,			"CD/DVD Device",
113	DTYPE_SCANNER,			"Scanner Device",
114	DTYPE_OPTICAL,			"Optical Memory Device",
115	DTYPE_CHANGER,			"Medium Changer Device",
116	DTYPE_COMM,			"Communications Device",
117	DTYPE_ARRAY_CTRL,		"Storage Array Controller Device",
118	DTYPE_ESI,			"Enclosure Services Device",
119	DTYPE_RBC,			"Simplified Direct-access Device",
120	DTYPE_OCRW,			"Optical Card Reader/Writer Device",
121	DTYPE_BCC,			"Bridge Controller Commands",
122	DTYPE_OSD,			"Object-based Storage Device",
123	DTYPE_ADC,			"Automation/Drive Interface",
124	DTYPE_WELLKNOWN,		"Well Known Logical Unit",
125	DTYPE_UNKNOWN,			"Unknown Device",
126	-1,				NULL
127};
128
129static char *getPhyStateString(HBA_UINT32 key, phystat_type phyt);
130
131char *
132getIndentSpaces(int number)
133{
134	int 		i = 0;
135	/* the maximum indent with terminator '\0' */
136	static char	ret[MAXINDENT+1];
137
138	if (number > MAXINDENT)
139		number = MAXINDENT;
140
141	for (i = 0; i < number; i++) {
142		ret[i] = ' ';
143	}
144	ret[i] = '\0';
145	return (ret);
146}
147
148char *
149getStateString(HBA_UINT32 key, SAS_STATE *stat_string)
150{
151	static char ret[64];
152	while (stat_string->key != -1) {
153		if (stat_string->key == key) {
154			return ((char *)stat_string->value);
155		}
156		stat_string++;
157	}
158	(void *) sprintf(ret, "Undefined value (%d)", key);
159	return (ret);
160}
161
162static char *
163getPhyStateString(HBA_UINT32 key, phystat_type phyt)
164{
165	int i = 0, len = 0, match = 0;
166	HBA_UINT32 physpeed[] = {
167		HBA_SASSPEED_1_5GBIT,
168		HBA_SASSPEED_3GBIT,
169		HBA_SASSPEED_6GBIT,
170		HBA_SASSPEED_12GBIT
171	};
172
173	len = sizeof (physpeed) / sizeof (HBA_UINT32);
174	for (i = 0; i < len; i++) {
175		if (key == physpeed[i]) {
176			match = 1;
177			break;
178		}
179	}
180
181	if (match == 1) {
182		if (phyt == PHY_STATE)
183			return ("enabled");
184		else
185			return (getStateString(key, phystate_string));
186	} else {
187		if (phyt == PHY_STATE)
188			return (getStateString(key, phystate_string));
189		else
190			return ("not available");
191	}
192}
193
194char *
195getHBAStatus(HBA_STATUS key)
196{
197	return (getStateString(key, hbastatus_string));
198}
199
200/*
201 * return device type description
202 *
203 * Arguments:
204 *	dType - Device type returned from Standard INQUIRY
205 * Returns:
206 *	char string description for device type
207 */
208char *
209getDTypeString(uchar_t dType)
210{
211	return (getStateString((dType & DTYPE_MASK), dtype_string));
212}
213
214uint64_t
215wwnConversion(uchar_t *wwn)
216{
217	uint64_t tmp;
218	(void *) memcpy(&tmp, wwn, sizeof (uint64_t));
219	return (ntohll(tmp));
220}
221
222/*
223 * prints out HBA information
224 */
225void
226printHBAInfo(SMHBA_ADAPTERATTRIBUTES *attrs, int pflag, int numberOfPorts,
227    const char *adapterName)
228{
229
230	(void *) fprintf(stdout, "%s %s\n", "HBA Name:", adapterName);
231
232	if (pflag & PRINT_VERBOSE) {
233		(void *) fprintf(stdout, "%s%s %s\n",
234		    getIndentSpaces(4), "Manufacturer:",
235		    attrs->Manufacturer[0] == 0?
236		    "not available":attrs->Manufacturer);
237		(void *) fprintf(stdout, "%s%s %s\n",
238		    getIndentSpaces(4), "Model: ",
239		    attrs->Model[0] == 0? "not available":attrs->Model);
240		(void *) fprintf(stdout, "%s%s %s\n",
241		    getIndentSpaces(4),
242		    "Firmware Version:",
243		    attrs->FirmwareVersion[0] == 0? "not available":
244		    attrs->FirmwareVersion);
245		(void *) fprintf(stdout, "%s%s %s\n",
246		    getIndentSpaces(4),
247		    "FCode/BIOS Version:",
248		    attrs->OptionROMVersion[0] == 0? "not available":
249		    attrs->OptionROMVersion);
250		(void *) fprintf(stdout, "%s%s %s\n",
251		    getIndentSpaces(4),
252		    "Serial Number:",
253		    attrs->SerialNumber[0] == 0? "not available":
254		    attrs->SerialNumber);
255		(void *) fprintf(stdout, "%s%s %s\n",
256		    getIndentSpaces(4),
257		    "Driver Name:",
258		    attrs->DriverName[0] == 0? "not available":
259		    attrs->DriverName);
260		(void *) fprintf(stdout, "%s%s %s\n",
261		    getIndentSpaces(4),
262		    "Driver Version:",
263		    attrs->DriverVersion[0] == 0? "not available":
264		    attrs->DriverVersion);
265		(void *) fprintf(stdout, "%s%s %d\n",
266		    getIndentSpaces(4),
267		    "Number of HBA Ports:",
268		    numberOfPorts);
269	}
270}
271
272/*
273 * prints out all the HBA port information
274 */
275void
276printHBAPortInfo(SMHBA_PORTATTRIBUTES *port,
277    SMHBA_ADAPTERATTRIBUTES *attrs, int pflag) {
278
279	if ((port == NULL) || (attrs == NULL)) {
280		return;
281	}
282
283	(void *) fprintf(stdout, "%s%s %s\n",
284	    getIndentSpaces(2),
285	    "HBA Port Name:",
286	    port->OSDeviceName);
287
288	if (!(pflag & PRINT_VERBOSE)) {
289		return;
290	}
291
292	if (port->PortType != HBA_PORTTYPE_SASDEVICE)
293		return;
294
295	(void *) fprintf(stdout, "%s%s %s\n",
296	    getIndentSpaces(4),
297	    "Type:",
298	    getStateString(port->PortType, porttype_string));
299	(void *) fprintf(stdout, "%s%s %s\n",
300	    getIndentSpaces(4),
301	    "State:",
302	    getStateString(port->PortState, portstate_string));
303
304	(void *) fprintf(stdout, "%s%s %016llx\n",
305	    getIndentSpaces(4),
306	    "Local SAS Address:",
307	    wwnConversion(port->PortSpecificAttribute.SASPort->\
308	    LocalSASAddress.wwn));
309
310	(void *) fprintf(stdout, "%s%s %016llx\n",
311	    getIndentSpaces(4),
312	    "Attached SAS Address:",
313	    wwnConversion(port->PortSpecificAttribute.SASPort->\
314	    AttachedSASAddress.wwn));
315
316	(void *) fprintf(stdout, "%s%s %d\n",
317	    getIndentSpaces(4),
318	    "Number of Phys:",
319	    port->PortSpecificAttribute.SASPort->NumberofPhys);
320}
321
322void
323printHBAPortPhyInfo(SMHBA_SAS_PHY *phyinfo)
324{
325	if (phyinfo == NULL)
326		return;
327
328	(void *) fprintf(stdout, "%s%s %u\n",
329	    getIndentSpaces(6),
330	    "Identifier:",
331	    phyinfo->PhyIdentifier);
332
333	(void *) fprintf(stdout, "%s%s %s\n",
334	    getIndentSpaces(8),
335	    "State: ",
336	    getPhyStateString(phyinfo->NegotiatedLinkRate, PHY_STATE));
337	(void *) fprintf(stdout, "%s%s %s/%s\n",
338	    getIndentSpaces(8),
339	    "HardwareLinkRate(Min/Max):",
340	    getPhyStateString(phyinfo->HardwareMinLinkRate, PHY_SPEED),
341	    getPhyStateString(phyinfo->HardwareMaxLinkRate, PHY_SPEED));
342	(void *) fprintf(stdout, "%s%s %s/%s\n",
343	    getIndentSpaces(8),
344	    "ProgrammedLinkRate(Min/Max):",
345	    getPhyStateString(phyinfo->ProgrammedMinLinkRate, PHY_SPEED),
346	    getPhyStateString(phyinfo->ProgrammedMaxLinkRate, PHY_SPEED));
347	(void *) fprintf(stdout, "%s%s %s\n",
348	    getIndentSpaces(8),
349	    "NegotiatedLinkRate:",
350	    getPhyStateString(phyinfo->NegotiatedLinkRate, PHY_SPEED));
351}
352
353void
354printHBAPortPhyStatistics(SMHBA_SASPHYSTATISTICS *phystat)
355{
356	if (phystat == NULL)
357		return;
358
359	(void *) fprintf(stdout, "%s%s\n",
360	    getIndentSpaces(8),
361	    "Link Error Statistics:");
362	(void *) fprintf(stdout, "%s%s %llu\n",
363	    getIndentSpaces(12),
364	    "Invalid Dword:",
365	    phystat->InvalidDwordCount);
366	(void *) fprintf(stdout, "%s%s %llu\n",
367	    getIndentSpaces(12),
368	    "Running Disparity Error:",
369	    phystat->RunningDisparityErrorCount);
370	(void *) fprintf(stdout, "%s%s %llu\n",
371	    getIndentSpaces(12),
372	    "Loss of Dword Sync:",
373	    phystat->LossofDwordSyncCount);
374	(void *) fprintf(stdout, "%s%s %llu\n",
375	    getIndentSpaces(12),
376	    "Reset Problem:",
377	    phystat->PhyResetProblemCount);
378}
379
380/*
381 * print the OS device name for the logical-unit object
382 *
383 * Arguments:
384 *	devListWalk - OS device path info
385 *	verbose - boolean indicating whether to display additional info
386 *
387 * returns:
388 * 	0 - we're good.
389 * 	>0 - we met issues.
390 */
391int
392printTargetPortInfo(targetPortList_t *TPListWalk, int pflag)
393{
394	targetPortConfig_t	*configList;
395	targetPortMappingData_t	*mapList;
396	int			count, i;
397	int			ret = 0;
398
399	(void *) fprintf(stdout, "Target Port SAS Address: %016llx\n",
400	    wwnConversion(TPListWalk->sasattr.LocalSASAddress.wwn));
401	if ((pflag & PRINT_VERBOSE) || (pflag & PRINT_TARGET_SCSI)) {
402		(void *) fprintf(stdout, "%sType: %s\n", getIndentSpaces(4),
403		    getStateString(TPListWalk->targetattr.PortType,
404		    porttype_string));
405		for (configList = TPListWalk->configEntry;
406		    configList != NULL; configList = configList->next) {
407			(void *) fprintf(stdout, "%sHBA Port Name: %s\n",
408			    getIndentSpaces(4), configList->hbaPortName);
409			if (wwnConversion(configList->expanderSASAddr.wwn) !=
410			    0) {
411				if (configList->expanderValid) {
412					(void *) fprintf(stdout,
413					    "%sExpander Device SAS Address:"
414					    " %016llx",
415					    getIndentSpaces(8),
416					    wwnConversion(configList->
417					    expanderSASAddr.wwn));
418				} else {
419					(void *) fprintf(stdout,
420					    "%sExpander Device SAS Address:"
421					    " %016llx (Failed to Validate"
422					    " Attached Port.)",
423					    getIndentSpaces(8),
424					    wwnConversion(configList->
425					    expanderSASAddr.wwn));
426					ret++;
427				}
428			} else {
429				if (configList->expanderValid) {
430					(void *) fprintf(stdout,
431					    "%sExpander Device SAS Address: %s",
432					    getIndentSpaces(8),
433					    "None (direct attached)");
434				} else {
435					(void *) fprintf(stdout,
436					    "%sExpander Device SAS Address: %s",
437					    getIndentSpaces(8),
438					    "None (Failed to Get"
439					    " Attached Port)");
440				}
441			}
442			(void *) fprintf(stdout, "\n");
443			if (pflag & PRINT_TARGET_SCSI) {
444
445				if (configList->reportLUNsFailed) {
446					(void *) fprintf(stdout,
447					    "%s %016llx\n",
448					    gettext("Error: Failed to get "
449					    "ReportLun Data on"),
450					    wwnConversion(TPListWalk->
451					    sasattr.LocalSASAddress.wwn));
452					ret++;
453					continue;
454				}
455
456				for (mapList = configList->map;
457				    mapList != NULL; mapList = mapList->next) {
458					(void *) fprintf(stdout, "%sLUN : %d\n",
459					    getIndentSpaces(12),
460					    mapList->osLUN);
461					if (mapList->mappingExist) {
462						(void *) fprintf(stdout,
463						    "%sOS Device Name : %s\n",
464						    getIndentSpaces(14),
465						    (mapList->osDeviceName[0] ==
466						    '\0') ?  "Not avaialble" :
467						    mapList->osDeviceName);
468					} else {
469						(void *) fprintf(stdout,
470						    "%sOS Device Name : %s\n",
471						    getIndentSpaces(14), "No "
472						    "matching OS Device "
473						    "found.");
474						ret++;
475					}
476		/* indentation changed here */
477		if (mapList->inquiryFailed) {
478			(void *) fprintf(stdout, "%s %s LUN %d\n",
479			    gettext("Error: Failed to get Inquiry Data on"),
480			    mapList->osDeviceName, mapList->osLUN);
481			ret++;
482		} else {
483			(void *) fprintf(stdout, "%sVendor: ",
484			    getIndentSpaces(14));
485			for (count = sizeof (mapList->inq_vid), i = 0;
486			    i < count; i++) {
487				if (isprint(mapList->inq_vid[i]))
488					(void *) fprintf(stdout, "%c",
489					    mapList->inq_vid[i]);
490			}
491
492			(void *) fprintf(stdout, "\n%sProduct: ",
493			    getIndentSpaces(14));
494			for (count = sizeof (mapList->inq_pid), i = 0;
495			    i < count; i++) {
496				if (isprint(mapList->inq_pid[i]))
497					(void *) fprintf(stdout, "%c",
498					    mapList->inq_pid[i]);
499			}
500
501			(void *) fprintf(stdout, "\n%sDevice Type: %s\n",
502			    getIndentSpaces(14),
503			    getDTypeString(mapList->inq_dtype));
504		}
505		/* indentation changed back */
506				}
507			}
508		}
509	}
510	return (ret);
511}
512
513/*
514 * print the OS device name for the logical-unit object
515 *
516 * Arguments:
517 *	devListWalk - OS device path info
518 *	verbose - boolean indicating whether to display additional info
519 *
520 * returns:
521 * 	0 - we're good.
522 * 	>0 - we met issues.
523 */
524int
525printOSDeviceNameInfo(discoveredDevice *devListWalk, boolean_t verbose)
526{
527	portList		*portElem;
528	tgtPortWWNList		*tgtWWNList;
529	int			i, count;
530	int			ret = 0;
531
532	(void *) fprintf(stdout, "OS Device Name: %s\n",
533	    devListWalk->OSDeviceName);
534	if (verbose == B_TRUE) {
535		for (portElem = devListWalk->HBAPortList;
536		    portElem != NULL; portElem = portElem->next) {
537			(void *) fprintf(stdout, "%sHBA Port Name: ",
538			    getIndentSpaces(4));
539			(void *) fprintf(stdout, "%s", portElem->portName);
540			for (tgtWWNList = portElem->tgtPortWWN;
541			    tgtWWNList != NULL; tgtWWNList = tgtWWNList->next) {
542				(void *) fprintf(stdout,
543				    "\n%sTarget Port SAS Address: ",
544				    getIndentSpaces(8));
545				(void *) fprintf(stdout, "%016llx",
546				    wwnConversion(tgtWWNList->portWWN.wwn));
547				(void *) fprintf(stdout, "\n%sLUN: %u",
548				    getIndentSpaces(12),
549				    tgtWWNList->scsiOSLun);
550			}
551			(void *) fprintf(stdout, "\n");
552		}
553
554		if (devListWalk->inquiryFailed) {
555			(void *) fprintf(stdout, "%s %s\n",
556			    gettext("Error: Failed to get Inquiry data "
557			    "on device"), devListWalk->OSDeviceName);
558			ret++;
559		} else {
560			(void *) fprintf(stdout, "%sVendor: ",
561			    getIndentSpaces(4));
562			for (count = sizeof (devListWalk->VID), i = 0;
563			    i < count; i++) {
564				if (isprint(devListWalk->VID[i]))
565					(void *) fprintf(stdout, "%c",
566					    devListWalk->VID[i]);
567			}
568
569			(void *) fprintf(stdout, "\n%sProduct: ",
570			    getIndentSpaces(4));
571			for (count = sizeof (devListWalk->PID), i = 0;
572			    i < count; i++) {
573				if (isprint(devListWalk->PID[i]))
574					(void *) fprintf(stdout, "%c",
575					    devListWalk->PID[i]);
576			}
577
578			(void *) fprintf(stdout, "\n%sDevice Type: %s\n",
579			    getIndentSpaces(4),
580			    getDTypeString(devListWalk->dType));
581		}
582	}
583	return (ret);
584}
585