xref: /illumos-gate/usr/src/cmd/luxadm/fabric_conf.c (revision 0babfc55)
1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
22fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce44SJohn Forte  * Use is subject to license terms.
24fcf3ce44SJohn Forte  */
25fcf3ce44SJohn Forte 
26fcf3ce44SJohn Forte 
27fcf3ce44SJohn Forte 
28fcf3ce44SJohn Forte 
29fcf3ce44SJohn Forte #include <stdlib.h>
30fcf3ce44SJohn Forte #include <stdio.h>
31fcf3ce44SJohn Forte #include <unistd.h>
32fcf3ce44SJohn Forte #include <sys/types.h>
33fcf3ce44SJohn Forte #include <sys/stat.h>
34fcf3ce44SJohn Forte #include <fcntl.h>
35fcf3ce44SJohn Forte #include <errno.h>
36fcf3ce44SJohn Forte #include <string.h>
37fcf3ce44SJohn Forte #include <stdarg.h>
38fcf3ce44SJohn Forte #include <syslog.h>
39fcf3ce44SJohn Forte #include <libdevice.h>
40fcf3ce44SJohn Forte #include <sys/fibre-channel/fcio.h>
41fcf3ce44SJohn Forte #include "common.h"
42fcf3ce44SJohn Forte 
43fcf3ce44SJohn Forte static int parse_line(char *line, char *path, char *wwn, char *filename);
44fcf3ce44SJohn Forte static int create_ap_instance(char *ap_id, char *wwn_string,
45fcf3ce44SJohn Forte 	char *filename, char *line);
46fcf3ce44SJohn Forte static void log_error(char *msg_id, char *input_tmplt, ...);
47fcf3ce44SJohn Forte static char ctoi(char c);
48fcf3ce44SJohn Forte 
49fcf3ce44SJohn Forte /*
50fcf3ce44SJohn Forte  *  Simple wrapper for syslog error messages.
51fcf3ce44SJohn Forte  *  Allows easy addition of syserr output if desired.
52fcf3ce44SJohn Forte  */
53fcf3ce44SJohn Forte static void
log_error(char * msg_id,char * input_tmplt,...)54fcf3ce44SJohn Forte log_error(char *msg_id, char *input_tmplt, ...)
55fcf3ce44SJohn Forte {
56fcf3ce44SJohn Forte 	va_list ap;
57fcf3ce44SJohn Forte 	char input_merged_msg[200];
58fcf3ce44SJohn Forte 	char *msg_template = "ID[luxadm.create_fabric_device.%s] %s";
59fcf3ce44SJohn Forte 	/*
60fcf3ce44SJohn Forte 	 * First %s for msg_id in merged msg.
61fcf3ce44SJohn Forte 	 * Second %s is for  input merged_msg
62fcf3ce44SJohn Forte 	 */
63fcf3ce44SJohn Forte 	char *merged_msg;
64fcf3ce44SJohn Forte 
65fcf3ce44SJohn Forte 	va_start(ap, input_tmplt);
66fcf3ce44SJohn Forte 	/* insert caller's args */
67fcf3ce44SJohn Forte 	(void) vsprintf(input_merged_msg, input_tmplt, ap);
68fcf3ce44SJohn Forte 	va_end(ap);
69fcf3ce44SJohn Forte 
70fcf3ce44SJohn Forte 	merged_msg = (char *)malloc(strlen(msg_template) +
71*0babfc55SToomas Soome 	    strlen(input_merged_msg) +
72*0babfc55SToomas Soome 	    strlen(msg_id) + 1);
73fcf3ce44SJohn Forte 	if (merged_msg == NULL) {
74*0babfc55SToomas Soome 		syslog(LOG_ERR, "ID[luxadm.create_fabric_device.2317] "
75*0babfc55SToomas Soome 		    "malloc failure, %s", strerror(errno));
76fcf3ce44SJohn Forte 	} else {
77fcf3ce44SJohn Forte 		sprintf(merged_msg, msg_template, msg_id, input_merged_msg);
78fcf3ce44SJohn Forte 			/* first insert msg_id */
79fcf3ce44SJohn Forte 		syslog(LOG_ERR, merged_msg, "");
80fcf3ce44SJohn Forte 		(void) puts(merged_msg);	/* also print message */
81fcf3ce44SJohn Forte 		free(merged_msg);
82fcf3ce44SJohn Forte 	}
83fcf3ce44SJohn Forte }
84fcf3ce44SJohn Forte 
85fcf3ce44SJohn Forte /*
86fcf3ce44SJohn Forte  *   Routines for reading tapestry repository file
87fcf3ce44SJohn Forte  */
88fcf3ce44SJohn Forte 
89fcf3ce44SJohn Forte #define	COMMENT_CHAR '#'
90fcf3ce44SJohn Forte int
read_repos_file(char * repos_filename)91fcf3ce44SJohn Forte read_repos_file(char *repos_filename)
92fcf3ce44SJohn Forte {
93fcf3ce44SJohn Forte 	int fd;
94fcf3ce44SJohn Forte 	char *line;
95fcf3ce44SJohn Forte 	char *tmp_ptr, *mmap_ptr;
96fcf3ce44SJohn Forte 	char path[MAXPATHLEN];
97fcf3ce44SJohn Forte 	int ret;
98fcf3ce44SJohn Forte 	char wwn[FC_WWN_SIZE*2+1];
99fcf3ce44SJohn Forte 	struct stat stbuf;
100fcf3ce44SJohn Forte 	unsigned int filesize;
101fcf3ce44SJohn Forte 	unsigned int bytes_read;
102fcf3ce44SJohn Forte 
103*0babfc55SToomas Soome 	if (repos_filename == NULL || *repos_filename == '\0') {
104fcf3ce44SJohn Forte 		log_error("2310",
105*0babfc55SToomas Soome 		    "filename missing for -f option of "
106*0babfc55SToomas Soome 		    "luxadm -e create_fabric_device");
107fcf3ce44SJohn Forte 		return (-1);
108fcf3ce44SJohn Forte 	}
109fcf3ce44SJohn Forte 
110fcf3ce44SJohn Forte 	fd = open(repos_filename, O_RDONLY);
111fcf3ce44SJohn Forte 
112fcf3ce44SJohn Forte 	if (fd == -1) {
113fcf3ce44SJohn Forte 		log_error("2311",
114*0babfc55SToomas Soome 		    "fopen failed: cannot open repository file %s. %d",
115*0babfc55SToomas Soome 		    repos_filename, strerror(errno));
116fcf3ce44SJohn Forte 		return (-1);
117fcf3ce44SJohn Forte 	}
118fcf3ce44SJohn Forte 
119fcf3ce44SJohn Forte 	if (fstat(fd, &stbuf) == -1) {
120fcf3ce44SJohn Forte 		close(fd);
121*0babfc55SToomas Soome 		log_error("2312", "stat failed on file %s. %s",
122*0babfc55SToomas Soome 		    repos_filename, strerror(errno));
123fcf3ce44SJohn Forte 		return (-1);
124fcf3ce44SJohn Forte 	}
125fcf3ce44SJohn Forte 	filesize = stbuf.st_size;
126fcf3ce44SJohn Forte 	tmp_ptr = mmap_ptr = mmap((caddr_t)0, filesize,
127*0babfc55SToomas Soome 	    (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
128fcf3ce44SJohn Forte 
129fcf3ce44SJohn Forte 	if (mmap_ptr == MAP_FAILED) {
130*0babfc55SToomas Soome 		log_error("2315", "Failed to mmap file %s. %s",
131*0babfc55SToomas Soome 		    repos_filename, strerror(errno));
132fcf3ce44SJohn Forte 		return (-1);
133fcf3ce44SJohn Forte 	}
134fcf3ce44SJohn Forte 
135fcf3ce44SJohn Forte 	bytes_read = 0;
136fcf3ce44SJohn Forte 	while (bytes_read < filesize) {
137fcf3ce44SJohn Forte 		line = tmp_ptr;
138fcf3ce44SJohn Forte 		while (bytes_read < filesize && *tmp_ptr != '\n') {
139fcf3ce44SJohn Forte 			bytes_read++;
140fcf3ce44SJohn Forte 			tmp_ptr++;
141fcf3ce44SJohn Forte 		}
142fcf3ce44SJohn Forte 		if (*tmp_ptr == '\n') {
143*0babfc55SToomas Soome 			*tmp_ptr = '\0';
144fcf3ce44SJohn Forte 			tmp_ptr++;
145fcf3ce44SJohn Forte 			bytes_read++;
146fcf3ce44SJohn Forte 		}
147fcf3ce44SJohn Forte 
148fcf3ce44SJohn Forte 		/* If the line is a comment, read another line */
149fcf3ce44SJohn Forte 		if (*line == COMMENT_CHAR) {
150fcf3ce44SJohn Forte 			continue;
151fcf3ce44SJohn Forte 		}
152fcf3ce44SJohn Forte 		ret = parse_line(line, path, wwn, repos_filename);
153fcf3ce44SJohn Forte 		if (ret == 0) {
154fcf3ce44SJohn Forte 			ret = create_ap_instance(path,
155fcf3ce44SJohn Forte 			    wwn, repos_filename, line);
156fcf3ce44SJohn Forte 		}
157fcf3ce44SJohn Forte 	}
158fcf3ce44SJohn Forte 
159fcf3ce44SJohn Forte 	ret = close(fd);
160fcf3ce44SJohn Forte 	ret = munmap(mmap_ptr, filesize);
161fcf3ce44SJohn Forte 	return (ret);
162fcf3ce44SJohn Forte }
163fcf3ce44SJohn Forte 
164fcf3ce44SJohn Forte /*
165fcf3ce44SJohn Forte  * Input is paramater 1 - a line from repository
166fcf3ce44SJohn Forte  * Output is other parameters, the path to the attachment point,
167fcf3ce44SJohn Forte  * and the port wwn are parsed from the repository
168fcf3ce44SJohn Forte  * Format is
169fcf3ce44SJohn Forte  *	"/devices/pci..../fp@1,0:fc::wwn"
170fcf3ce44SJohn Forte  * If controller name is missing, that's okay.  Other fields
171fcf3ce44SJohn Forte  * must be present
172fcf3ce44SJohn Forte  *
173fcf3ce44SJohn Forte  * Return 0 on success or -1 on failure; all failures logged to syslog.
174fcf3ce44SJohn Forte  */
175fcf3ce44SJohn Forte #define	WWN_DELIM "::"
176fcf3ce44SJohn Forte static int
parse_line(char * line,char * path,char * wwn,char * filename)177fcf3ce44SJohn Forte parse_line(char *line, char *path, char *wwn, char *filename)
178fcf3ce44SJohn Forte {
179fcf3ce44SJohn Forte 	char *p_path, *p_wwn, *p_delim;
180fcf3ce44SJohn Forte 	char *line_copy;
181fcf3ce44SJohn Forte 
182fcf3ce44SJohn Forte 	line_copy = strdup(line);
183fcf3ce44SJohn Forte 	if (line_copy == NULL) {
184*0babfc55SToomas Soome 		log_error("2317", "malloc failure, %s", strerror(errno));
185fcf3ce44SJohn Forte 	}
186fcf3ce44SJohn Forte 	p_path = line_copy;
187fcf3ce44SJohn Forte 	p_delim = strstr(p_path, WWN_DELIM);
188fcf3ce44SJohn Forte 	if (p_delim == NULL) {
189fcf3ce44SJohn Forte 		log_error("2313",
190*0babfc55SToomas Soome 		    "Invalid line (%s) in file %s.", line, filename);
191fcf3ce44SJohn Forte 		free(line_copy);
192fcf3ce44SJohn Forte 		return (-1);
193fcf3ce44SJohn Forte 	}
194*0babfc55SToomas Soome 	*p_delim = '\0';	/* NULL terminate path */
195fcf3ce44SJohn Forte 
196fcf3ce44SJohn Forte 	if (strlcpy(path, p_path, MAXPATHLEN) >= MAXPATHLEN) {
197fcf3ce44SJohn Forte 		log_error("2318",
198*0babfc55SToomas Soome 		    "Path too long (%s) in file %s.", p_path, filename);
199fcf3ce44SJohn Forte 		free(line_copy);
200fcf3ce44SJohn Forte 		return (-1);
201fcf3ce44SJohn Forte 	}
202fcf3ce44SJohn Forte 
203fcf3ce44SJohn Forte 	p_wwn = p_delim + strlen(WWN_DELIM);
204fcf3ce44SJohn Forte 	/*
205fcf3ce44SJohn Forte 	 * Now look for the blank delimiter before the controller
206fcf3ce44SJohn Forte 	 *
207fcf3ce44SJohn Forte 	 * This is just the case when there may be a controller #
208fcf3ce44SJohn Forte 	 * after the attachment point and WWN. For example -
209fcf3ce44SJohn Forte 	 * /devices/pci@b,2000/pci@2/SUNW,qlc@4/fp@0,0:fc::220000203707f4f1 c4
210fcf3ce44SJohn Forte 	 */
211fcf3ce44SJohn Forte 	p_delim = strchr(p_wwn, ' ');
212fcf3ce44SJohn Forte 	if (p_delim != NULL) {
213fcf3ce44SJohn Forte 		/* now p_delim points to blank */
214*0babfc55SToomas Soome 		*p_delim = '\0';	/* terminate wwn at delim */
215fcf3ce44SJohn Forte 	} else {
216fcf3ce44SJohn Forte 		char *p_last_char;
217fcf3ce44SJohn Forte 		p_last_char = p_wwn+strlen(p_wwn)-1;
218fcf3ce44SJohn Forte 		if (*p_last_char == '\n') {
219*0babfc55SToomas Soome 			*p_last_char = '\0';
220fcf3ce44SJohn Forte 		}
221fcf3ce44SJohn Forte 	}
222fcf3ce44SJohn Forte 	strcpy(wwn, p_wwn);
223fcf3ce44SJohn Forte 	free(line_copy);
224fcf3ce44SJohn Forte 	return (0);
225fcf3ce44SJohn Forte }
226fcf3ce44SJohn Forte 
227fcf3ce44SJohn Forte static char
ctoi(char c)228fcf3ce44SJohn Forte ctoi(char c)
229fcf3ce44SJohn Forte {
230fcf3ce44SJohn Forte 	if ((c >= '0') && (c <= '9'))
231fcf3ce44SJohn Forte 		c -= '0';
232fcf3ce44SJohn Forte 	else if ((c >= 'A') && (c <= 'F'))
233fcf3ce44SJohn Forte 		c = c - 'A' + 10;
234fcf3ce44SJohn Forte 	else if ((c >= 'a') && (c <= 'f'))
235fcf3ce44SJohn Forte 		c = c - 'a' + 10;
236fcf3ce44SJohn Forte 	else
237fcf3ce44SJohn Forte 		c = -1;
238fcf3ce44SJohn Forte 	return (c);
239fcf3ce44SJohn Forte }
240fcf3ce44SJohn Forte 
241fcf3ce44SJohn Forte /*
242fcf3ce44SJohn Forte  * "string" is Input and "port_wwn" has the output
243fcf3ce44SJohn Forte  *
244fcf3ce44SJohn Forte  * This function converts a string to WWN.
245fcf3ce44SJohn Forte  * For example a string like
246fcf3ce44SJohn Forte  * "220000203707F4F1" gets converted to 0x220000203707F4F1 ...
247fcf3ce44SJohn Forte  * where
248fcf3ce44SJohn Forte  * port_wwn[0] = 0x22,
249fcf3ce44SJohn Forte  * port_wwn[1] = 0x00,
250fcf3ce44SJohn Forte  * port_wwn[2] = 0x00,
251fcf3ce44SJohn Forte  * port_wwn[3] = 0x20,
252fcf3ce44SJohn Forte  * port_wwn[4] = 0x37,
253fcf3ce44SJohn Forte  * port_wwn[5] = 0x07,
254fcf3ce44SJohn Forte  * port_wwn[6] = 0xF4, and
255fcf3ce44SJohn Forte  * port_wwn[7] = 0xF1
256fcf3ce44SJohn Forte  */
257fcf3ce44SJohn Forte static int
string_to_wwn(const uchar_t * string,uchar_t * port_wwn)258fcf3ce44SJohn Forte string_to_wwn(const uchar_t *string, uchar_t *port_wwn)
259fcf3ce44SJohn Forte {
260fcf3ce44SJohn Forte 	int	i;
261fcf3ce44SJohn Forte 	char	c, c1;
262fcf3ce44SJohn Forte 	uchar_t	*wwnp;
263fcf3ce44SJohn Forte 
264fcf3ce44SJohn Forte 	wwnp = port_wwn;
265fcf3ce44SJohn Forte 	for (i = 0; i < WWN_SIZE; i++, wwnp++) {
266fcf3ce44SJohn Forte 
267fcf3ce44SJohn Forte 		c = ctoi(*string++);
268fcf3ce44SJohn Forte 		c1 = ctoi(*string++);
269fcf3ce44SJohn Forte 		if (c == -1 || c1 == -1)
270fcf3ce44SJohn Forte 			return (-1);
271fcf3ce44SJohn Forte 		*wwnp = ((c << 4) + c1);
272fcf3ce44SJohn Forte 	}
273fcf3ce44SJohn Forte 
274fcf3ce44SJohn Forte 	return (0);
275fcf3ce44SJohn Forte }
276fcf3ce44SJohn Forte 
277fcf3ce44SJohn Forte static int
create_ap_instance(char * ap_id,char * wwn_string,char * filename,char * line)278fcf3ce44SJohn Forte create_ap_instance(char *ap_id, char *wwn_string,
279*0babfc55SToomas Soome     char *filename, char *line)
280fcf3ce44SJohn Forte {
281fcf3ce44SJohn Forte 	devctl_hdl_t bus_handle, dev_handle;
282fcf3ce44SJohn Forte 	devctl_ddef_t ddef_handle;
283fcf3ce44SJohn Forte 	int ret;
284fcf3ce44SJohn Forte 	uchar_t wwn_array[FC_WWN_SIZE];
285fcf3ce44SJohn Forte 
286fcf3ce44SJohn Forte 	ddef_handle = devctl_ddef_alloc("dummy", 0);
287fcf3ce44SJohn Forte 	if (ddef_handle == NULL) {
288fcf3ce44SJohn Forte 		log_error("2314",
289*0babfc55SToomas Soome 		    "Internal error to process line (%s) in file: %s. %s",
290*0babfc55SToomas Soome 		    line, filename, strerror(errno));
291fcf3ce44SJohn Forte 		return (-1);
292fcf3ce44SJohn Forte 	}
293fcf3ce44SJohn Forte 	/*
294fcf3ce44SJohn Forte 	 * g_string_to_wwn() has not been used here because it
295fcf3ce44SJohn Forte 	 * prepends 2 NULLs.
296fcf3ce44SJohn Forte 	 */
297fcf3ce44SJohn Forte 	if (string_to_wwn((uchar_t *)wwn_string, wwn_array) != 0) {
298fcf3ce44SJohn Forte 		log_error("2314",
299*0babfc55SToomas Soome 		    "Internal error to process line (%s) in file: %s. %s",
300*0babfc55SToomas Soome 		    line, filename, strerror(errno));
301fcf3ce44SJohn Forte 		devctl_ddef_free(ddef_handle);
302fcf3ce44SJohn Forte 		return (-1);
303fcf3ce44SJohn Forte 	}
304fcf3ce44SJohn Forte 	(void) devctl_ddef_byte_array(ddef_handle,
305*0babfc55SToomas Soome 	    "port-wwn", FC_WWN_SIZE, wwn_array);
306fcf3ce44SJohn Forte 
307fcf3ce44SJohn Forte 	if ((bus_handle = devctl_bus_acquire(ap_id, 0)) == NULL) {
308fcf3ce44SJohn Forte 		devctl_ddef_free(ddef_handle);
309fcf3ce44SJohn Forte 		log_error("2314",
310*0babfc55SToomas Soome 		    "Internal error to process line (%s) in file: %s. %s",
311*0babfc55SToomas Soome 		    line, filename, strerror(errno));
312fcf3ce44SJohn Forte 		return (-1);
313fcf3ce44SJohn Forte 	}
314fcf3ce44SJohn Forte 	if (ret =
315fcf3ce44SJohn Forte 	    devctl_bus_dev_create(bus_handle, ddef_handle, 0, &dev_handle)) {
316fcf3ce44SJohn Forte 		devctl_ddef_free(ddef_handle);
317fcf3ce44SJohn Forte 		devctl_release(bus_handle);
318fcf3ce44SJohn Forte 		log_error("2316",
319*0babfc55SToomas Soome 		    "configuration failed for line (%s) in file: %s. %s",
320*0babfc55SToomas Soome 		    line, filename, strerror(errno));
321fcf3ce44SJohn Forte 		return (-1);
322fcf3ce44SJohn Forte 	}
323fcf3ce44SJohn Forte 	devctl_release(dev_handle);
324fcf3ce44SJohn Forte 	devctl_ddef_free(ddef_handle);
325fcf3ce44SJohn Forte 	devctl_release(bus_handle);
326fcf3ce44SJohn Forte 	return (ret);
327fcf3ce44SJohn Forte }
328