xref: /illumos-gate/usr/src/cmd/fwflash/plugins/transport/common/sd.c (revision 8119dad84d6416f13557b0ba8e2aaf9064cbcfd3)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright 2016 Joyent, Inc.
27  */
28 
29 /*
30  * sd / ssd (SCSI Direct-attached Device) specific functions.
31  */
32 
33 #include <libnvpair.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <sys/sysmacros.h>
39 #include <sys/queue.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <scsi/libscsi.h>
45 #include <sys/scsi/scsi_types.h>
46 #include <libintl.h> /* for gettext(3c) */
47 #include <fwflash/fwflash.h>
48 #include <sys/debug.h>
49 #include <umem.h>
50 
51 typedef struct sam4_statdesc {
52 	int sam_status;
53 	char *sam_message;
54 } sam4_statdesc_t;
55 
56 static sam4_statdesc_t sam4_status[] = {
57 	{ SAM4_STATUS_GOOD, "Status: GOOD (success)" },
58 	{ SAM4_STATUS_CHECK_CONDITION, "Status: CHECK CONDITION" },
59 	{ SAM4_STATUS_CONDITION_MET, "Status: CONDITION MET" },
60 	{ SAM4_STATUS_BUSY, "Status: Device is BUSY" },
61 	{ SAM4_STATUS_RESERVATION_CONFLICT, "Status: Device is RESERVED" },
62 	{ SAM4_STATUS_TASK_SET_FULL,
63 	    "Status: TASK SET FULL (insufficient resources in command queue" },
64 	{ SAM4_STATUS_TASK_ABORTED, "Status: TASK ABORTED" }
65 };
66 
67 #define	NSAM4_STATUS	(sizeof (sam4_status) / sizeof (sam4_status[0]))
68 
69 #define	FW_SD_FREE_DEVPATH(devpath)	{	\
70 		di_devfs_path_free((devpath));	\
71 	}
72 #define	FW_SD_FREE_DEVICELIST(thisdev, devpath) {	\
73 		free((thisdev));	\
74 		FW_SD_FREE_DEVPATH((devpath))	\
75 	}
76 #define	FW_SD_FREE_DRV_NAME(thisdev, devpath) {	\
77 		free((thisdev)->drvname);	\
78 		FW_SD_FREE_DEVICELIST((thisdev), (devpath))	\
79 	}
80 #define	FW_SD_FREE_CLS_NAME(thisdev, devpath) {	\
81 		free((thisdev)->classname);	\
82 		FW_SD_FREE_DRV_NAME((thisdev), (devpath))	\
83 	}
84 #define	FW_SD_FREE_ACC_NAME(thisdev, devpath) {	\
85 		free((thisdev)->access_devname);	\
86 		FW_SD_FREE_CLS_NAME(thisdev, devpath)	\
87 	}
88 #define	FW_SD_FREE_ADDR(thisdev, devpath) {	\
89 		free((thisdev)->addresses[0]);	\
90 		FW_SD_FREE_ACC_NAME(thisdev, devpath)	\
91 	}
92 #define	FW_SD_FREE_IDENT(thisdev, devpath) {	\
93 		free((thisdev)->ident);	\
94 		FW_SD_FREE_ADDR((thisdev), (devpath))	\
95 	}
96 #define	FW_SD_FREE_IDENT_VID(thisdev, devpath) {	\
97 		free((thisdev)->ident->vid);	\
98 		FW_SD_FREE_IDENT((thisdev), (devpath))	\
99 	}
100 #define	FW_SD_FREE_IDENT_PID(thisdev, devpath) {	\
101 		free((thisdev)->ident->pid);	\
102 		FW_SD_FREE_IDENT_VID((thisdev), (devpath))	\
103 	}
104 #define	FW_SD_FREE_IDENT_ALL(thisdev, devpath) {	\
105 		free((thisdev)->ident->revid);	\
106 		FW_SD_FREE_IDENT_PID((thisdev), (devpath))	\
107 	}
108 
109 /*
110  * This is our default partial write size when we encounter a situation where we
111  * need to upgrade disks whose firmware image cannot be done in a single write.
112  * While in theory we should just use the maximum transfer size and make sure
113  * it's aligned, that's proven to be problematic for some Seagate disks. Hence
114  * we just make sure that if partial writes are required that this value fits in
115  * the required alignment and in the actual maximum transfer size.
116  */
117 #define	FW_SD_PARTIAL_WRITE_SIZE	(64 * 1024)
118 
119 /*
120  * Declarations required for fwflash
121  */
122 char drivername[] = "sd\0";
123 int plugin_version = FWPLUGIN_VERSION_2;
124 
125 /*
126  * Data provided by fwflash
127  */
128 extern di_node_t rootnode;
129 extern struct fw_plugin *self;
130 extern struct vrfyplugin *verifier;
131 extern int fwflash_debug;
132 
133 static char *sdfw_devprefix = "/devices";
134 
135 static char *sdfw_find_link(di_node_t bnode, char *acc_devname);
136 static int sdfw_link_cb(di_devlink_t devlink, void *arg);
137 static int sdfw_idtfy_custmz(struct devicelist *device, char *sp);
138 
139 /*
140  * We don't currently support reading firmware from a disk. If we do eventually
141  * support it, we would use the scsi READ BUFFER command to do so.
142  */
143 int
144 fw_readfw(struct devicelist *flashdev, char *filename)
145 {
146 
147 	logmsg(MSG_INFO,
148 	    "%s: not writing firmware for device %s to file %s\n",
149 	    flashdev->drvname, flashdev->access_devname, filename);
150 	logmsg(MSG_ERROR,
151 	    gettext("\n\nReading of firmware images from %s-attached "
152 	    "devices is not supported\n\n"),
153 	    flashdev->drvname);
154 
155 	return (FWFLASH_SUCCESS);
156 }
157 
158 
159 static int
160 sdfw_read_descriptor(struct devicelist *flashdev, libscsi_hdl_t *hdl,
161     libscsi_target_t *targ, uint8_t *align)
162 {
163 	spc3_read_buffer_cdb_t *rb_cdb;
164 	size_t nwritten;
165 	libscsi_action_t *action = NULL;
166 	uint8_t descbuf[4];
167 	sam4_status_t samstatus;
168 
169 	VERIFY3P(hdl, !=, NULL);
170 	VERIFY3P(targ, !=, NULL);
171 	VERIFY3P(align, !=, NULL);
172 
173 	if ((action = libscsi_action_alloc(hdl, SPC3_CMD_READ_BUFFER,
174 	    LIBSCSI_AF_READ, descbuf, sizeof (descbuf))) == NULL) {
175 		logmsg(MSG_ERROR, gettext("%s: failed to alloc scsi action: "
176 		    "%s\n"),
177 		    flashdev->drvname, libscsi_errmsg(hdl));
178 		return (FWFLASH_FAILURE);
179 	}
180 
181 	rb_cdb = (spc3_read_buffer_cdb_t *)libscsi_action_get_cdb(action);
182 
183 	rb_cdb->rbc_mode = SPC3_RB_MODE_DESCRIPTOR;
184 
185 	/*
186 	 * Microcode upgrade usually only uses the first buffer ID which is
187 	 * sequentially indexed from zero. Strictly speaking these are all
188 	 * vendor defined, but so far most vendors we've seen use index zero
189 	 * for this.
190 	 */
191 	rb_cdb->rbc_bufferid = 0;
192 
193 	rb_cdb->rbc_allocation_len[0] = 0;
194 	rb_cdb->rbc_allocation_len[1] = 0;
195 	rb_cdb->rbc_allocation_len[2] = sizeof (descbuf);
196 
197 	if (libscsi_exec(action, targ) != 0) {
198 		logmsg(MSG_ERROR, gettext("%s: failed to execute SCSI buffer "
199 		    "data read: %s\n"),
200 		    flashdev->drvname, libscsi_errmsg(hdl));
201 		libscsi_action_free(action);
202 		return (FWFLASH_FAILURE);
203 	}
204 
205 	if ((samstatus = libscsi_action_get_status(action)) !=
206 	    SAM4_STATUS_GOOD) {
207 		int i;
208 		for (i = 0; i < NSAM4_STATUS; i++) {
209 			if (samstatus == sam4_status[i].sam_status) {
210 				logmsg(MSG_ERROR, gettext("%s: SCSI buffer "
211 				    "data read failed: %s\n"),
212 				    flashdev->drvname,
213 				    sam4_status[i].sam_message);
214 				libscsi_action_free(action);
215 				return (FWFLASH_FAILURE);
216 			}
217 		}
218 		logmsg(MSG_ERROR, gettext("%s: SCSI buffer data read failed: "
219 		    "unknown error: %d\n"), flashdev->drvname, samstatus);
220 		libscsi_action_free(action);
221 		return (FWFLASH_FAILURE);
222 	}
223 
224 	if (libscsi_action_get_buffer(action, NULL, NULL, &nwritten) != 0) {
225 		logmsg(MSG_ERROR, gettext("%s: failed to get actual data "
226 		    "size: %s\n"),
227 		    flashdev->drvname, libscsi_errmsg(hdl));
228 		libscsi_action_free(action);
229 		return (FWFLASH_FAILURE);
230 	}
231 	libscsi_action_free(action);
232 
233 	if (nwritten != sizeof (descbuf)) {
234 		logmsg(MSG_ERROR, gettext("%s: received a short read from the "
235 		    "SCSI READ BUFFER command, expected %u bytes, read %zu\n"),
236 		    flashdev->drvname, sizeof (descbuf), nwritten);
237 		return (FWFLASH_FAILURE);
238 	}
239 
240 	if (descbuf[0] == 0 && descbuf[1] == 0 && descbuf[2] == 0 &&
241 	    descbuf[3] == 0) {
242 		logmsg(MSG_ERROR, gettext("%s: devices %s does not support "
243 		    "firmware upgrade\n"), verifier->vendor,
244 		    flashdev->access_devname);
245 		return (FWFLASH_FAILURE);
246 	}
247 
248 	*align = descbuf[0];
249 
250 	return (FWFLASH_SUCCESS);
251 }
252 
253 static int
254 sdfw_write(struct devicelist *flashdev, libscsi_hdl_t *handle,
255     libscsi_target_t *target, size_t len, size_t off, void *buf)
256 {
257 	sam4_status_t samstatus;
258 	libscsi_action_t *action = NULL;
259 	spc3_write_buffer_cdb_t *wb_cdb;
260 
261 	logmsg(MSG_INFO, "%s: writing %u bytes of image %s at offset %zu from "
262 	    "address %p\n", flashdev->drvname, len, verifier->imgfile, off,
263 	    buf);
264 	logmsg(MSG_INFO, "%s: writing to buffer id %u\n",
265 	    flashdev->drvname, verifier->flashbuf);
266 
267 	VERIFY3P(flashdev, !=, NULL);
268 	VERIFY3P(handle, !=, NULL);
269 	VERIFY3P(target, !=, NULL);
270 	VERIFY3P(buf, !=, NULL);
271 	VERIFY3U(len, >, 0);
272 	VERIFY3U(off + len, <=, verifier->imgsize);
273 
274 	action = libscsi_action_alloc(handle, SPC3_CMD_WRITE_BUFFER,
275 	    LIBSCSI_AF_WRITE | LIBSCSI_AF_RQSENSE | LIBSCSI_AF_ISOLATE, buf,
276 	    len);
277 	if (action == NULL) {
278 		logmsg(MSG_ERROR, gettext("%s: failed to alloc scsi action: "
279 		    "%s\n"), flashdev->drvname, libscsi_errmsg(handle));
280 		goto err;
281 	}
282 
283 	wb_cdb = (spc3_write_buffer_cdb_t *)libscsi_action_get_cdb(action);
284 
285 	wb_cdb->wbc_mode = SPC3_WB_MODE_DL_UCODE_OFFS_SAVE;
286 
287 	wb_cdb->wbc_buffer_offset[0] = (off >> 16) & 0xff;
288 	wb_cdb->wbc_buffer_offset[1] = (off >> 8) & 0xff;
289 	wb_cdb->wbc_buffer_offset[2] = off & 0xff;
290 
291 	wb_cdb->wbc_bufferid = verifier->flashbuf;
292 
293 	wb_cdb->wbc_parameter_list_len[0] = (len >> 16) & 0xff;
294 	wb_cdb->wbc_parameter_list_len[1] = (len >> 8) & 0xff;
295 	wb_cdb->wbc_parameter_list_len[2] = len & 0xff;
296 
297 	logmsg(MSG_INFO, "%s: spc3_write_buffer_cdb_t opcode: %u\n",
298 	    flashdev->drvname, wb_cdb->wbc_opcode);
299 
300 	if (libscsi_exec(action, target) != 0) {
301 		logmsg(MSG_ERROR, gettext("%s: failed to execute SCSI WRITE "
302 		    "BUFFER: %s\n"),
303 		    flashdev->drvname, libscsi_errmsg(handle));
304 		goto err;
305 	}
306 
307 	if ((samstatus = libscsi_action_get_status(action)) ==
308 	    SAM4_STATUS_CHECK_CONDITION) {
309 		uint64_t asc = 0, ascq = 0, key = 0;
310 		const char *code, *keystr;
311 
312 		if (libscsi_action_parse_sense(action, &key, &asc, &ascq,
313 		    NULL) != 0) {
314 			logmsg(MSG_ERROR, gettext("%s: failed to write "
315 			    "firmware. Received CHECK_CONDITION that cannot be "
316 			    "parsed.\n"),
317 			    flashdev->drvname);
318 			goto err;
319 		}
320 
321 		code = libscsi_sense_code_name(asc, ascq);
322 		keystr = libscsi_sense_key_name(key);
323 
324 		logmsg(MSG_ERROR, gettext("%s: failed to write firmware: "
325 		    "received sense key %" PRIu64 " (%s) additional sense code "
326 		    "0x%" PRIx64 "/0x%" PRIx64 " (%s)\n"), flashdev->drvname,
327 		    key, keystr != NULL ? keystr : "<unknown>",
328 		    asc, ascq, code != NULL ? code : "<unknown>");
329 		goto err;
330 	} else if (samstatus != SAM4_STATUS_GOOD) {
331 		int i;
332 
333 		logmsg(MSG_ERROR, gettext("%s: SCSI buffer data write failed:"),
334 		    flashdev->drvname);
335 		for (i = 0; i < NSAM4_STATUS; i++) {
336 			if (samstatus == sam4_status[i].sam_status) {
337 				logmsg(MSG_ERROR, gettext("%s\n"),
338 				    sam4_status[i].sam_message);
339 				goto err;
340 			}
341 		}
342 		logmsg(MSG_ERROR, gettext("unknown error: %d\n"), samstatus);
343 		goto err;
344 	} else {
345 		logmsg(MSG_INFO, "%s: received STATUS GOOD\n",
346 		    flashdev->drvname);
347 	}
348 
349 	libscsi_action_free(action);
350 	return (FWFLASH_SUCCESS);
351 
352 err:
353 	if (action != NULL)
354 		libscsi_action_free(action);
355 	return (FWFLASH_FAILURE);
356 }
357 
358 int
359 fw_writefw(struct devicelist *flashdev)
360 {
361 	libscsi_hdl_t	*handle;
362 	libscsi_target_t *target;
363 	libscsi_errno_t serr;
364 	size_t maxxfer, nwrite;
365 	uint8_t align;
366 	int ret = FWFLASH_FAILURE;
367 
368 	if ((verifier == NULL) || (verifier->imgsize == 0) ||
369 	    (verifier->fwimage == NULL)) {
370 		/* should _NOT_ happen */
371 		logmsg(MSG_ERROR,
372 		    gettext("%s: Firmware image has not been verified\n"),
373 		    flashdev->drvname);
374 		return (FWFLASH_FAILURE);
375 	}
376 
377 	if ((handle = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) {
378 		logmsg(MSG_ERROR, gettext("%s: failed to initialize libscsi\n"),
379 		    flashdev->drvname);
380 		return (FWFLASH_FAILURE);
381 	}
382 
383 	if ((target = libscsi_open(handle, NULL, flashdev->access_devname)) ==
384 	    NULL) {
385 		logmsg(MSG_ERROR,
386 		    gettext("%s: unable to open device %s\n"),
387 		    flashdev->drvname, flashdev->access_devname);
388 		libscsi_fini(handle);
389 		return (FWFLASH_FAILURE);
390 	}
391 
392 	if (libscsi_max_transfer(target, &maxxfer) != 0) {
393 		logmsg(MSG_ERROR, gettext("%s: failed to determine device "
394 		    "maximum transfer size: %s\n"), flashdev->drvname,
395 		    libscsi_errmsg(handle));
396 		goto err;
397 	}
398 
399 	if (sdfw_read_descriptor(flashdev, handle, target, &align) !=
400 	    FWFLASH_SUCCESS) {
401 		goto err;
402 	}
403 
404 	/*
405 	 * If the maximum transfer size is less than the maximum image size then
406 	 * we have to do some additional work. We need to read the descriptor
407 	 * via a READ BUFFER command and make sure that we support the required
408 	 * offset alignment. Note that an alignment of 0xff indicates that the
409 	 * device does not support partial writes and must receive the firmware
410 	 * in a single WRITE BUFFER.  Otherwise a value in align represents a
411 	 * required offset alignment of 2^off. From there, we make sure that
412 	 * this works for our partial write size and that our partial write size
413 	 * fits in the maximum transfer size.
414 	 */
415 	if (maxxfer < verifier->imgsize) {
416 		logmsg(MSG_INFO, "%s: Maximum transfer is %zu, required "
417 		    "alignment is 2^%u\n", flashdev->drvname, maxxfer, align);
418 		if (FW_SD_PARTIAL_WRITE_SIZE > maxxfer) {
419 			logmsg(MSG_ERROR, gettext("%s: cannot write firmware "
420 			    "image: HBA enforces a maximum transfer size of "
421 			    "%zu bytes, but the default partial transfer size "
422 			    "is %u bytes\n"), flashdev->drvname, maxxfer,
423 			    FW_SD_PARTIAL_WRITE_SIZE);
424 			goto err;
425 		}
426 		maxxfer = FW_SD_PARTIAL_WRITE_SIZE;
427 
428 		if (ffsll(maxxfer) < align || align == 0xff) {
429 			logmsg(MSG_ERROR, gettext("%s: cannot write firmware "
430 			    "image: device requires partial writes aligned "
431 			    "to an unsupported value\n"), flashdev->drvname);
432 			goto err;
433 		}
434 
435 		logmsg(MSG_INFO, "%s: final transfer block size is %zu\n",
436 		    flashdev->drvname, maxxfer);
437 	}
438 
439 	logmsg(MSG_INFO, "%s: Writing out %u bytes to %s\n", flashdev->drvname,
440 	    verifier->imgsize, flashdev->access_devname);
441 	nwrite = 0;
442 	for (;;) {
443 		uintptr_t buf;
444 		size_t towrite = MIN(maxxfer, verifier->imgsize - nwrite);
445 
446 		if (towrite == 0)
447 			break;
448 
449 		buf = (uintptr_t)verifier->fwimage;
450 		buf += nwrite;
451 
452 		if (sdfw_write(flashdev, handle, target, towrite, nwrite,
453 		    (void *)buf) != FWFLASH_SUCCESS) {
454 			logmsg(MSG_ERROR, gettext("%s: failed to write to %s "
455 			    "successfully: %s\n"), flashdev->drvname,
456 			    flashdev->access_devname, libscsi_errmsg(handle));
457 			goto err;
458 		}
459 
460 		nwrite += towrite;
461 	}
462 
463 	logmsg(MSG_ERROR, gettext("Note: For flash based disks "
464 	    "(SSD, etc). You may need power off the system to wait a "
465 	    "few minutes for supercap to fully discharge, then power "
466 	    "on the system again to activate the new firmware\n"));
467 	ret = FWFLASH_SUCCESS;
468 
469 err:
470 	if (target != NULL)
471 		libscsi_close(handle, target);
472 	if (handle != NULL)
473 		libscsi_fini(handle);
474 
475 	return (ret);
476 }
477 
478 /*
479  * The fw_identify() function walks the device
480  * tree trying to find devices which this plugin
481  * can work with.
482  *
483  * The parameter "start" gives us the starting index number
484  * to give the device when we add it to the fw_devices list.
485  *
486  * firstdev is allocated by us and we add space as needed
487  *
488  * When we store the desired information, inquiry-serial-no
489  * goes in thisdev->addresses[1], and client-guid goes in
490  * thisdev->addresses[2].
491  */
492 int
493 fw_identify(int start)
494 {
495 	int idx = start;
496 	int fw_sata_disk = 0;
497 	int *exists;
498 	di_node_t thisnode;
499 	struct devicelist *newdev = NULL;
500 	char *devpath = NULL;
501 	char *driver = NULL;
502 	char *sp_temp;
503 	char *sp_temp_cut;
504 
505 	/* We need to inquiry information manually by sending probe command */
506 	libscsi_hdl_t *handle;
507 	libscsi_target_t *target;
508 	libscsi_errno_t serr;
509 
510 	/* Just in case we've got an FC-attached device on sparc */
511 	if (strcmp(self->drvname, "ssd") == 0) {
512 		driver = self->drvname;
513 	} else
514 		driver = drivername;
515 
516 	thisnode = di_drv_first_node(driver, rootnode);
517 
518 	if (thisnode == DI_NODE_NIL) {
519 		logmsg(MSG_INFO, "No %s nodes in this system\n", driver);
520 		return (FWFLASH_FAILURE);
521 	}
522 
523 	if ((handle = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) {
524 		logmsg(MSG_ERROR, gettext("%s: failed to initialize "
525 		    "libscsi\n"), newdev->drvname);
526 		return (FWFLASH_FAILURE);
527 	}
528 
529 	/* we've found one, at least */
530 	for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) {
531 		/* Need to free by di_devfs_path_free */
532 		if ((devpath = di_devfs_path(thisnode)) == NULL) {
533 			logmsg(MSG_INFO, "unable to get device path for "
534 			    "current node with errno %d\n", errno);
535 			continue;
536 		}
537 		/*
538 		 * We check if this is removable device, in which case
539 		 * we really aren't interested, so exit stage left
540 		 */
541 		if (di_prop_lookup_ints(DDI_DEV_T_ANY, thisnode,
542 		    "removable-media", &exists) > -1) {
543 			logmsg(MSG_INFO,
544 			    "%s: not interested in removable media device\n"
545 			    "%s\n", driver, devpath);
546 			FW_SD_FREE_DEVPATH(devpath)
547 			continue;
548 		}
549 
550 		if ((newdev = calloc(1, sizeof (struct devicelist))) ==
551 		    NULL) {
552 			logmsg(MSG_ERROR,
553 			    gettext("%s: identification function unable "
554 			    "to allocate space for device entry\n"),
555 			    driver);
556 			libscsi_fini(handle);
557 			FW_SD_FREE_DEVPATH(devpath)
558 			return (FWFLASH_FAILURE);
559 		}
560 
561 		if ((newdev->drvname = calloc(1, strlen(driver) + 1)) ==
562 		    NULL) {
563 			logmsg(MSG_ERROR,
564 			    gettext("%s: Unable to allocate space to store a "
565 			    "driver name\n"), driver);
566 			libscsi_fini(handle);
567 			FW_SD_FREE_DEVICELIST(newdev, devpath)
568 			return (FWFLASH_FAILURE);
569 		}
570 		(void) strlcpy(newdev->drvname, driver, strlen(driver) + 1);
571 
572 		if ((newdev->classname = calloc(1, strlen(driver) + 1)) ==
573 		    NULL) {
574 			logmsg(MSG_ERROR,
575 			    gettext("%s: Unable to allocate space for a class "
576 			    "name\n"), drivername);
577 			libscsi_fini(handle);
578 			FW_SD_FREE_DRV_NAME(newdev, devpath)
579 			return (FWFLASH_FAILURE);
580 		}
581 		(void) strlcpy(newdev->classname, driver, strlen(driver) + 1);
582 
583 		/* Get the access name for current node */
584 		if ((newdev->access_devname = calloc(1, MAXPATHLEN)) == NULL) {
585 			logmsg(MSG_ERROR,
586 			    gettext("%s: Unable to allocate space for a devfs "
587 			    "name\n"), driver);
588 			libscsi_fini(handle);
589 			FW_SD_FREE_CLS_NAME(newdev, devpath)
590 			return (FWFLASH_FAILURE);
591 		}
592 
593 		/* The slice number may be 2 or 0, we will try 2 first */
594 		(void) snprintf(newdev->access_devname, MAXPATHLEN,
595 		    "%s%s:c,raw", sdfw_devprefix, devpath);
596 		if ((target = libscsi_open(handle, NULL,
597 		    newdev->access_devname)) == NULL) {
598 			/* try 0 for EFI label */
599 			(void) snprintf(newdev->access_devname, MAXPATHLEN,
600 			    "%s%s:a,raw", sdfw_devprefix, devpath);
601 			if ((target = libscsi_open(handle, NULL,
602 			    newdev->access_devname)) == NULL) {
603 				logmsg(MSG_INFO,
604 				    "%s: unable to open device %s\n",
605 				    newdev->drvname, newdev->access_devname);
606 				FW_SD_FREE_ACC_NAME(newdev, devpath)
607 				continue;
608 			}
609 		}
610 
611 		/* and the /dev/rdsk/ name */
612 		if ((newdev->addresses[0] = sdfw_find_link(thisnode,
613 		    newdev->access_devname)) == NULL) {
614 			libscsi_fini(handle);
615 			FW_SD_FREE_ACC_NAME(newdev, devpath)
616 			return (FWFLASH_FAILURE);
617 		}
618 
619 		/*
620 		 * Only alloc as much as we truly need, and DON'T forget
621 		 * that libdevinfo manages the memory!
622 		 */
623 		if ((newdev->ident = calloc(1, sizeof (struct vpr))) == NULL) {
624 			logmsg(MSG_ERROR,
625 			    gettext("%s: Unable to allocate space for SCSI "
626 			    "INQUIRY data\n"), driver);
627 			libscsi_fini(handle);
628 			FW_SD_FREE_ADDR(newdev, devpath)
629 			return (FWFLASH_FAILURE);
630 		}
631 
632 		/* We don't use new->ident->encap_ident currently */
633 
634 		/* Retrive information by using libscsi */
635 		/* Vendor ID */
636 		sp_temp = (char *)libscsi_vendor(target);
637 		if (strncmp(sp_temp, "ATA", 3) == 0) {
638 			/* We need to do customize the output for SATA disks */
639 			fw_sata_disk = 1;
640 		} else {
641 			fw_sata_disk = 0;
642 			if ((newdev->ident->vid =
643 			    calloc(1, strlen(sp_temp) + 1)) == NULL ||
644 			    sp_temp == NULL) {
645 				if (!sp_temp) {
646 					logmsg(MSG_ERROR, gettext("%s: unable "
647 					    "to get vendor id of %s\n"),
648 					    newdev->drvname,
649 					    newdev->access_devname);
650 				} else {
651 					logmsg(MSG_ERROR, gettext("Memory "
652 					    "allocation failure\n"));
653 				}
654 
655 				libscsi_close(handle, target);
656 				libscsi_fini(handle);
657 				FW_SD_FREE_IDENT(newdev, devpath)
658 				return (FWFLASH_FAILURE);
659 			}
660 			strlcpy(newdev->ident->vid, sp_temp,
661 			    strlen(sp_temp) + 1);
662 		}
663 
664 		/* Product ID */
665 		sp_temp = (char *)libscsi_product(target);
666 		if (fw_sata_disk) {
667 			sp_temp_cut = strchr(sp_temp, ' ');
668 			if (!sp_temp_cut) {
669 				/*
670 				 * There is no SPACE character in the PID field
671 				 * Customize strings for special SATA disks
672 				 */
673 				if (sdfw_idtfy_custmz(newdev, sp_temp)
674 				    != FWFLASH_SUCCESS) {
675 					libscsi_close(handle, target);
676 					libscsi_fini(handle);
677 					FW_SD_FREE_IDENT(newdev, devpath)
678 					return (FWFLASH_FAILURE);
679 				}
680 			} else {
681 				/* The first string is vendor id */
682 				if ((newdev->ident->vid = calloc(1,
683 				    (sp_temp_cut - sp_temp + 1))) == NULL) {
684 					logmsg(MSG_ERROR, gettext("%s: unable "
685 					    "to get sata vendor id of %s\n"),
686 					    newdev->drvname,
687 					    newdev->access_devname);
688 
689 					libscsi_close(handle, target);
690 					libscsi_fini(handle);
691 					FW_SD_FREE_IDENT(newdev, devpath)
692 					return (FWFLASH_FAILURE);
693 				}
694 				strlcpy(newdev->ident->vid, sp_temp,
695 				    sp_temp_cut - sp_temp + 1);
696 
697 				/* The second string is product id */
698 				if ((newdev->ident->pid =
699 				    calloc(1, strlen(sp_temp) -
700 				    strlen(newdev->ident->vid))) == NULL) {
701 					logmsg(MSG_ERROR, gettext("%s: unable "
702 					    "to get sata product id of %s\n"),
703 					    newdev->drvname,
704 					    newdev->access_devname);
705 
706 					libscsi_close(handle, target);
707 					libscsi_fini(handle);
708 					FW_SD_FREE_IDENT_VID(newdev, devpath)
709 					return (FWFLASH_FAILURE);
710 				}
711 				strlcpy(newdev->ident->pid, sp_temp_cut + 1,
712 				    strlen(sp_temp) -
713 				    strlen(newdev->ident->vid));
714 			}
715 		} else {
716 			if ((newdev->ident->pid =
717 			    calloc(1, strlen(sp_temp) + 1)) == NULL ||
718 			    sp_temp == NULL) {
719 				logmsg(MSG_ERROR, gettext("%s: unable to get "
720 				    "product id of %s\n"), newdev->drvname,
721 				    newdev->access_devname);
722 				FW_SD_FREE_IDENT_VID(newdev, devpath)
723 				libscsi_close(handle, target);
724 				libscsi_fini(handle);
725 				return (FWFLASH_FAILURE);
726 			}
727 			strlcpy(newdev->ident->pid, sp_temp,
728 			    strlen(sp_temp) + 1);
729 		}
730 
731 		/* Revision ID */
732 		sp_temp = (char *)libscsi_revision(target);
733 		if ((newdev->ident->revid = calloc(1, strlen(sp_temp) + 1)) ==
734 		    NULL || sp_temp == NULL) {
735 			logmsg(MSG_ERROR, gettext("%s: unable to get revision "
736 			    "id of %s\n"), newdev->drvname,
737 			    newdev->access_devname);
738 			libscsi_close(handle, target);
739 			libscsi_fini(handle);
740 			FW_SD_FREE_IDENT_PID(newdev, devpath)
741 			return (FWFLASH_FAILURE);
742 		}
743 		strlcpy(newdev->ident->revid, sp_temp, strlen(sp_temp) + 1);
744 
745 		/* Finish using libscsi */
746 		libscsi_close(handle, target);
747 
748 		if (di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode,
749 		    "inquiry-serial-no", &newdev->addresses[1]) < 0) {
750 			logmsg(MSG_INFO,
751 			    "%s: no inquiry-serial-no property for %s\n",
752 			    driver, newdev->access_devname);
753 			logmsg(MSG_INFO, "The errno is %d\n", errno);
754 		}
755 
756 		if ((di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode,
757 		    "client-guid", &newdev->addresses[2])) < 0) {
758 			logmsg(MSG_INFO,
759 			    "%s: no client-guid property "
760 			    "for device %s\n",
761 			    driver, newdev->access_devname);
762 			/* try fallback */
763 			if ((di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode,
764 			    "guid", &newdev->addresses[2])) < 0) {
765 				logmsg(MSG_INFO,
766 				    "%s: no guid property for device %s\n",
767 				    driver, newdev->access_devname);
768 			}
769 		} else {
770 			logmsg(MSG_INFO,
771 			    "client-guid property: %s\n",
772 			    newdev->addresses[2]);
773 		}
774 
775 		newdev->index = idx;
776 		++idx;
777 		newdev->plugin = self;
778 
779 		TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev);
780 		FW_SD_FREE_DEVPATH(devpath)
781 	}
782 	libscsi_fini(handle);
783 
784 	/* Check if sd targets presented are all unflashable. */
785 	if (idx == start)
786 		return (FWFLASH_FAILURE);
787 
788 	if (fwflash_debug != 0) {
789 		struct devicelist *tempdev;
790 
791 		TAILQ_FOREACH(tempdev, fw_devices, nextdev) {
792 			logmsg(MSG_INFO, "%s:fw_identify:\n",
793 			    driver);
794 			logmsg(MSG_INFO,
795 			    "\ttempdev @ 0x%lx\n"
796 			    "\t\taccess_devname: %s\n"
797 			    "\t\tdrvname: %s\tclassname: %s\n"
798 			    "\t\tident->vid:   %s\n"
799 			    "\t\tident->pid:   %s\n"
800 			    "\t\tident->revid: %s\n"
801 			    "\t\tindex:	%d\n"
802 			    "\t\taddress[0]:   %s\n"
803 			    "\t\taddress[1]:   %s\n"
804 			    "\t\taddress[2]:   %s\n"
805 			    "\t\tplugin @ 0x%lx\n\n",
806 			    &tempdev,
807 			    tempdev->access_devname,
808 			    tempdev->drvname, newdev->classname,
809 			    tempdev->ident->vid,
810 			    tempdev->ident->pid,
811 			    tempdev->ident->revid,
812 			    tempdev->index,
813 			    tempdev->addresses[0],
814 			    (tempdev->addresses[1] ? tempdev->addresses[1] :
815 			    "(not supported)"),
816 			    (tempdev->addresses[2] ? tempdev->addresses[2] :
817 			    "(not supported)"),
818 			    &tempdev->plugin);
819 		}
820 	}
821 	return (FWFLASH_SUCCESS);
822 }
823 
824 int
825 fw_devinfo(struct devicelist *thisdev)
826 {
827 	fprintf(stdout, gettext("Device[%d]\t\t\t%s\n"
828 	    "  Class [%s]\t\t\t%s\n"),
829 	    thisdev->index, thisdev->access_devname,
830 	    thisdev->classname, thisdev->addresses[0]);
831 
832 	fprintf(stdout,
833 	    gettext(
834 	    "\tVendor\t\t\t: %s\n"
835 	    "\tProduct\t\t\t: %s\n"
836 	    "\tFirmware revision\t: %-s\n"
837 	    "\tInquiry Serial Number   : %-s\n"
838 	    "\tGUID\t\t\t: %s\n"),
839 	    thisdev->ident->vid,
840 	    thisdev->ident->pid,
841 	    thisdev->ident->revid,
842 	    (thisdev->addresses[1] ? thisdev->addresses[1] :
843 	    "(not supported)"),
844 	    (thisdev->addresses[2] ? thisdev->addresses[2] :
845 	    "(not supported)"));
846 
847 	fprintf(stdout, "\n\n");
848 
849 	return (FWFLASH_SUCCESS);
850 }
851 
852 void
853 fw_cleanup(struct devicelist *thisdev)
854 {
855 	/*
856 	 * Function to clean up all the memory allocated
857 	 * by this plugin, for thisdev.
858 	 */
859 	free(thisdev->access_devname);
860 	free(thisdev->drvname);
861 	free(thisdev->classname);
862 
863 	/*
864 	 * Note that we DO NOT free addresses[1,2] because _IF_
865 	 * these elements are valid, they are managed by libdevinfo
866 	 * and we didn't allocate any space for them.
867 	 */
868 	free(thisdev->addresses[0]);
869 
870 	/* what this points to is freed in common code */
871 	thisdev->plugin = NULL;
872 
873 	free(thisdev->ident->vid);
874 	free(thisdev->ident->pid);
875 	free(thisdev->ident->revid);
876 
877 	thisdev->ident = NULL;
878 }
879 
880 /*
881  * Helper functions
882  */
883 static int
884 sdfw_link_cb(di_devlink_t devlink, void *arg)
885 {
886 	const char *result;
887 
888 	result = di_devlink_path(devlink);
889 	if (result == NULL) {
890 		arg = (void *)"(null)";
891 	} else {
892 		(void) strlcpy(arg, result, strlen(result) + 1);
893 	}
894 
895 	logmsg(MSG_INFO, "\nsdfw_link_cb::linkdata->resultstr = %s\n",
896 	    ((result != NULL) ? result : "(null)"));
897 
898 	return (DI_WALK_CONTINUE);
899 }
900 
901 static char *
902 sdfw_find_link(di_node_t bnode, char *acc_devname)
903 {
904 	di_minor_t devminor = DI_MINOR_NIL;
905 	di_devlink_handle_t hdl;
906 	char *cbresult = NULL;
907 	char linkname[] = "^rdsk/\0";
908 
909 	if (bnode == DI_NODE_NIL) {
910 		logmsg(MSG_ERROR,
911 		    gettext("sdfw_find_link must be called with non-null "
912 		    "di_node_t\n"));
913 		return (NULL);
914 	}
915 
916 	if ((cbresult = calloc(1, MAXPATHLEN)) == NULL) {
917 		logmsg(MSG_ERROR, gettext("unable to allocate space for dev "
918 		    "link\n"));
919 		return (NULL);
920 	}
921 
922 	devminor = di_minor_next(bnode, devminor);
923 	errno = 0;
924 	hdl = di_devlink_init(di_devfs_minor_path(devminor), DI_MAKE_LINK);
925 	if (hdl == NULL) {
926 		if (errno == EPERM || errno == EACCES) {
927 			logmsg(MSG_ERROR,
928 			    gettext("%s: You must be super-user to use this "
929 			    "plugin.\n"), drivername);
930 		} else {
931 			logmsg(MSG_ERROR,
932 			    gettext("unable to take devlink snapshot: %s\n"),
933 			    strerror(errno));
934 		}
935 		free(cbresult);
936 		return (NULL);
937 	}
938 
939 	errno = 0;
940 	if (di_devlink_walk(hdl, linkname, acc_devname + strlen(sdfw_devprefix),
941 	    DI_PRIMARY_LINK, (void *)cbresult, sdfw_link_cb) < 0) {
942 		logmsg(MSG_ERROR,
943 		    gettext("Unable to walk devlink snapshot for %s: %s\n"),
944 		    acc_devname, strerror(errno));
945 		free(cbresult);
946 		return (NULL);
947 	}
948 
949 	if (di_devlink_fini(&hdl) < 0) {
950 		logmsg(MSG_ERROR,
951 		    gettext("Unable to close devlink snapshot: %s\n"),
952 		    strerror(errno));
953 	}
954 
955 	logmsg(MSG_INFO, "cbresult: %s\n", cbresult);
956 	return (cbresult);
957 }
958 
959 static int
960 sdfw_idtfy_custmz(struct devicelist *device, char *sp)
961 {
962 	/* vid customization */
963 	if (strncmp(sp, "ST", 2) == 0) {
964 		/* Customize retail Seagate disks */
965 		if ((device->ident->vid = strdup("SEAGATE")) == NULL) {
966 			return (FWFLASH_FAILURE);
967 		}
968 	} else if (strncmp(sp, "SSD", 3) == 0) {
969 		/* Customize retail INTEL disks */
970 		if ((device->ident->vid = strdup("INTEL")) == NULL) {
971 			return (FWFLASH_FAILURE);
972 		}
973 	} else {
974 		/* disks to do in the future, fill 'ATA' first */
975 		if ((device->ident->vid = strdup("ATA")) == NULL) {
976 			return (FWFLASH_FAILURE);
977 		}
978 	}
979 
980 	/* pid customization */
981 	if ((device->ident->pid = calloc(1, strlen(sp) + 1)) == NULL) {
982 		logmsg(MSG_ERROR, gettext("Unable to allocate space for "
983 		    "product id\n"));
984 		free(device->ident->vid);
985 		return (FWFLASH_FAILURE);
986 	}
987 	strlcpy(device->ident->pid, sp, strlen(sp) + 1);
988 
989 	return (FWFLASH_SUCCESS);
990 }
991