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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
32 #include <sys/types.h>
39 #include <libdevice.h>
40 #include <sys/fibre-channel/fcio.h>
43 static int parse_line(char *line
, char *path
, char *wwn
, char *filename
);
44 static int create_ap_instance(char *ap_id
, char *wwn_string
,
45 char *filename
, char *line
);
46 static void log_error(char *msg_id
, char *input_tmplt
, ...);
47 static char ctoi(char c
);
50 * Simple wrapper for syslog error messages.
51 * Allows easy addition of syserr output if desired.
54 log_error(char *msg_id
, char *input_tmplt
, ...)
57 char input_merged_msg
[200];
58 char *msg_template
= "ID[luxadm.create_fabric_device.%s] %s";
60 * First %s for msg_id in merged msg.
61 * Second %s is for input merged_msg
65 va_start(ap
, input_tmplt
);
66 /* insert caller's args */
67 (void) vsprintf(input_merged_msg
, input_tmplt
, ap
);
70 merged_msg
= (char *)malloc(strlen(msg_template
) +
71 strlen(input_merged_msg
) +
73 if (merged_msg
== NULL
) {
75 "ID[luxadm.create_fabric_device.2317] "
76 "malloc failure, %s", strerror(errno
));
78 sprintf(merged_msg
, msg_template
, msg_id
, input_merged_msg
);
79 /* first insert msg_id */
80 syslog(LOG_ERR
, merged_msg
, "");
81 (void) puts(merged_msg
); /* also print message */
87 * Routines for reading tapestry repository file
90 #define COMMENT_CHAR '#'
92 read_repos_file(char *repos_filename
)
96 char *tmp_ptr
, *mmap_ptr
;
97 char path
[MAXPATHLEN
];
99 char wwn
[FC_WWN_SIZE
*2+1];
101 unsigned int filesize
;
102 unsigned int bytes_read
;
104 if (repos_filename
== NULL
|| *repos_filename
== '\0') {
106 "filename missing for -f option of "
107 "luxadm -e create_fabric_device");
111 fd
= open(repos_filename
, O_RDONLY
);
115 "fopen failed: cannot open repository file %s. %d",
116 repos_filename
, strerror(errno
));
120 if (fstat(fd
, &stbuf
) == -1) {
123 "stat failed on file %s. %s",
124 repos_filename
, strerror(errno
));
127 filesize
= stbuf
.st_size
;
128 tmp_ptr
= mmap_ptr
= mmap(NULL
, filesize
,
129 (PROT_READ
| PROT_WRITE
), MAP_PRIVATE
, fd
, 0);
131 if (mmap_ptr
== MAP_FAILED
) {
133 "Failed to mmap file %s. %s",
134 repos_filename
, strerror(errno
));
139 while (bytes_read
< filesize
) {
141 while (bytes_read
< filesize
&& *tmp_ptr
!= '\n') {
145 if (*tmp_ptr
== '\n') {
151 /* If the line is a comment, read another line */
152 if (*line
== COMMENT_CHAR
) {
155 ret
= parse_line(line
, path
, wwn
, repos_filename
);
157 ret
= create_ap_instance(path
,
158 wwn
, repos_filename
, line
);
163 ret
= munmap(mmap_ptr
, filesize
);
168 * Input is paramater 1 - a line from repository
169 * Output is other parameters, the path to the attachment point,
170 * and the port wwn are parsed from the repository
172 * "/devices/pci..../fp@1,0:fc::wwn"
173 * If controller name is missing, that's okay. Other fields
176 * Return 0 on success or -1 on failure; all failures logged to syslog.
178 #define WWN_DELIM "::"
180 parse_line(char *line
, char *path
, char *wwn
, char *filename
)
182 char *p_path
, *p_wwn
, *p_delim
;
185 line_copy
= strdup(line
);
186 if (line_copy
== NULL
) {
188 "malloc failure, %s", strerror(errno
));
191 p_delim
= strstr(p_path
, WWN_DELIM
);
192 if (p_delim
== NULL
) {
194 "Invalid line (%s) in file %s.", line
, filename
);
198 *p_delim
= '\0'; /* NULL terminate path */
200 if (strlcpy(path
, p_path
, MAXPATHLEN
) >= MAXPATHLEN
) {
202 "Path too long (%s) in file %s.", p_path
, filename
);
207 p_wwn
= p_delim
+ strlen(WWN_DELIM
);
209 * Now look for the blank delimiter before the controller
211 * This is just the case when there may be a controller #
212 * after the attachment point and WWN. For example -
213 * /devices/pci@b,2000/pci@2/SUNW,qlc@4/fp@0,0:fc::220000203707f4f1 c4
215 p_delim
= strchr(p_wwn
, ' ');
216 if (p_delim
!= NULL
) {
217 /* now p_delim points to blank */
218 *p_delim
= '\0'; /* terminate wwn at delim */
221 p_last_char
= p_wwn
+strlen(p_wwn
)-1;
222 if (*p_last_char
== '\n') {
234 if ((c
>= '0') && (c
<= '9'))
236 else if ((c
>= 'A') && (c
<= 'F'))
238 else if ((c
>= 'a') && (c
<= 'f'))
246 * "string" is Input and "port_wwn" has the output
248 * This function converts a string to WWN.
249 * For example a string like
250 * "220000203707F4F1" gets converted to 0x220000203707F4F1 ...
252 * port_wwn[0] = 0x22,
253 * port_wwn[1] = 0x00,
254 * port_wwn[2] = 0x00,
255 * port_wwn[3] = 0x20,
256 * port_wwn[4] = 0x37,
257 * port_wwn[5] = 0x07,
258 * port_wwn[6] = 0xF4, and
262 string_to_wwn(const uchar_t
*string
, uchar_t
*port_wwn
)
269 for (i
= 0; i
< WWN_SIZE
; i
++, wwnp
++) {
272 c1
= ctoi(*string
++);
273 if (c
== -1 || c1
== -1)
275 *wwnp
= ((c
<< 4) + c1
);
282 create_ap_instance(char *ap_id
, char *wwn_string
,
283 char *filename
, char *line
)
285 devctl_hdl_t bus_handle
, dev_handle
;
286 devctl_ddef_t ddef_handle
;
288 uchar_t wwn_array
[FC_WWN_SIZE
];
290 ddef_handle
= devctl_ddef_alloc("dummy", 0);
291 if (ddef_handle
== NULL
) {
293 "Internal error to process line (%s) "
295 line
, filename
, strerror(errno
));
299 * g_string_to_wwn() has not been used here because it
302 if (string_to_wwn((uchar_t
*)wwn_string
, wwn_array
) != 0) {
304 "Internal error to process line (%s) "
306 line
, filename
, strerror(errno
));
307 devctl_ddef_free(ddef_handle
);
310 (void) devctl_ddef_byte_array(ddef_handle
,
311 "port-wwn", FC_WWN_SIZE
, wwn_array
);
313 if ((bus_handle
= devctl_bus_acquire(ap_id
, 0)) == NULL
) {
314 devctl_ddef_free(ddef_handle
);
316 "Internal error to process line (%s) "
318 line
, filename
, strerror(errno
));
322 devctl_bus_dev_create(bus_handle
, ddef_handle
, 0, &dev_handle
)) {
323 devctl_ddef_free(ddef_handle
);
324 devctl_release(bus_handle
);
326 "configuration failed for line (%s) "
328 line
, filename
, strerror(errno
));
331 devctl_release(dev_handle
);
332 devctl_ddef_free(ddef_handle
);
333 devctl_release(bus_handle
);