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
fw_readfw(struct devicelist * flashdev,char * filename)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
sdfw_read_descriptor(struct devicelist * flashdev,libscsi_hdl_t * hdl,libscsi_target_t * targ,uint8_t * align)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
sdfw_write(struct devicelist * flashdev,libscsi_hdl_t * handle,libscsi_target_t * target,size_t len,size_t off,void * buf)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
fw_writefw(struct devicelist * flashdev)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
fw_identify(int start)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
fw_devinfo(struct devicelist * thisdev)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
fw_cleanup(struct devicelist * thisdev)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
sdfw_link_cb(di_devlink_t devlink,void * arg)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 *
sdfw_find_link(di_node_t bnode,char * acc_devname)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
sdfw_idtfy_custmz(struct devicelist * device,char * sp)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