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 /*
27 * ses (SCSI Generic Device) specific functions.
28 */
29
30 #include <libnvpair.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/sysmacros.h>
36 #include <sys/queue.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <scsi/libscsi.h>
40 #include <scsi/libses.h>
41 #include <libintl.h> /* for gettext(3c) */
42 #include <fwflash/fwflash.h>
43
44
45 #define VIDLEN 0x08
46 #define PIDLEN 0x10
47 #define REVLEN 0x04
48 #define SASADDRLEN 0x10
49 #define PCBUFLEN 0x40
50 #define RQBUFLEN 0xfe
51 #define STATBUFLEN 0xfe
52 #define INQBUFLEN 0x80
53
54 /* useful defines */
55 #define UCODE_CHECK_STATUS 0
56 #define UCODE_CHECK_SUPPORTED 1
57
58 typedef struct ucode_statdesc {
59 uint64_t us_value;
60 const char *us_desc;
61 boolean_t us_pending;
62 boolean_t us_iserr;
63 } ucode_statdesc_t;
64
65 static ucode_statdesc_t ucode_statdesc_table[] = {
66 { SES2_DLUCODE_S_NOP, "none", B_FALSE, B_FALSE },
67 { SES2_DLUCODE_S_INPROGRESS, "in progress", B_TRUE, B_FALSE },
68 { SES2_DLUCODE_S_SAVING, "saved", B_TRUE, B_FALSE },
69 { SES2_DLUCODE_S_COMPLETE_NOW, "completed (available)", B_FALSE,
70 B_FALSE },
71 { SES2_DLUCODE_S_COMPLETE_AT_RESET,
72 "completed (need reset or power on)", B_FALSE, B_FALSE },
73 { SES2_DLUCODE_S_COMPLETE_AT_POWERON, "completed (need power on)",
74 B_FALSE, B_FALSE },
75 { SES2_DLUCODE_S_PAGE_ERR, "page error (offset %d)",
76 B_FALSE, B_TRUE },
77 { SES2_DLUCODE_S_IMAGE_ERR, "invalid image",
78 B_FALSE, B_TRUE },
79 { SES2_DLUCODE_S_TIMEOUT, "download timeout",
80 B_FALSE, B_TRUE },
81 { SES2_DLUCODE_S_INTERNAL_NEEDIMAGE,
82 "internal error (NEED NEW IMAGE BEFORE RESET)",
83 B_FALSE, B_TRUE },
84 { SES2_DLUCODE_S_INTERNAL_SAFE,
85 "internal error (reset to revert to backup)",
86 B_FALSE, B_TRUE },
87 };
88
89 #define NUCODE_STATUS \
90 (sizeof (ucode_statdesc_table) / sizeof (ucode_statdesc_table[0]))
91
92 typedef struct ucode_status {
93 uint64_t us_status;
94 boolean_t us_iserr;
95 boolean_t us_pending;
96 char us_desc[128];
97 } ucode_status_t;
98
99 typedef struct ucode_wait {
100 uint64_t uw_prevstatus;
101 boolean_t uw_pending;
102 ses_node_t *uw_oldnp;
103 } ucode_wait_t;
104
105
106 typedef struct sam4_statdesc {
107 int status;
108 char *message;
109 } sam4_statdesc_t;
110
111
112 static sam4_statdesc_t sam4_status[] = {
113 { SAM4_STATUS_GOOD, "Status: GOOD (success)" },
114 { SAM4_STATUS_CHECK_CONDITION, "Status: CHECK CONDITION" },
115 { SAM4_STATUS_CONDITION_MET, "Status: CONDITION MET" },
116 { SAM4_STATUS_BUSY, "Status: Device is BUSY" },
117 { SAM4_STATUS_RESERVATION_CONFLICT, "Status: Device is RESERVED" },
118 { SAM4_STATUS_TASK_SET_FULL,
119 "Status: TASK SET FULL (insufficient resources in command queue" },
120 { SAM4_STATUS_TASK_ABORTED, "Status: TASK ABORTED" },
121 { 0, NULL }
122 };
123
124 #define NSAM4_STATUS \
125 (sizeof (sam4_status) / sizeof (sam4_status[0]))
126
127
128
129 char drivername[] = "ses\0";
130 static char *devprefix = "/devices";
131 static char *sessuffix = ":0";
132 static char *sgensuffix = ":ses";
133
134
135 static ses_target_t *ses_target;
136
137 extern di_node_t rootnode;
138 extern int errno;
139 extern struct fw_plugin *self;
140 extern struct vrfyplugin *verifier;
141 extern int fwflash_debug;
142
143
144 /* required functions for this plugin */
145 int fw_readfw(struct devicelist *device, char *filename);
146 int fw_writefw(struct devicelist *device);
147 int fw_identify(int start);
148 int fw_devinfo(struct devicelist *thisdev);
149
150
151 /* helper functions */
152 static int print_updated_status(ses_node_t *np, void *arg);
153 static int get_status(nvlist_t *props, ucode_status_t *sp);
154 static int sendimg(ses_node_t *np, void *data);
155 static int scsi_writebuf();
156
157 /*
158 * We don't currently support reading firmware from a SAS
159 * expander. If we do eventually support it, we would use
160 * the scsi READ BUFFER command to do so.
161 */
162 int
fw_readfw(struct devicelist * flashdev,char * filename)163 fw_readfw(struct devicelist *flashdev, char *filename)
164 {
165
166 logmsg(MSG_INFO,
167 "%s: not writing firmware for device %s to file %s\n",
168 flashdev->drvname, flashdev->access_devname, filename);
169 logmsg(MSG_ERROR,
170 gettext("\n\nReading of firmware images from %s-attached "
171 "devices is not supported\n\n"),
172 flashdev->drvname);
173
174 return (FWFLASH_SUCCESS);
175 }
176
177
178 /*
179 * If we're invoking fw_writefw, then flashdev is a valid,
180 * flashable device supporting the SES2 Download Microcode Diagnostic
181 * Control page (0x0e).
182 *
183 * If verifier is null, then we haven't been called following a firmware
184 * image verification load operation.
185 *
186 * *THIS* function uses scsi SEND DIAGNOSTIC/download microcode to
187 * achieve the task... if you chase down to the bottom of libses you
188 * can see that too.
189 */
190 int
fw_writefw(struct devicelist * flashdev)191 fw_writefw(struct devicelist *flashdev)
192 {
193 int rv = FWFLASH_FAILURE;
194 nvlist_t *nvl;
195 ses_snap_t *snapshot;
196 ses_node_t *targetnode;
197
198 if ((verifier == NULL) || (verifier->imgsize == 0) ||
199 (verifier->fwimage == NULL)) {
200 /* should _not_ happen */
201 logmsg(MSG_ERROR,
202 gettext("%s: Firmware image has not "
203 "been verified.\n"),
204 flashdev->drvname);
205 return (FWFLASH_FAILURE);
206 }
207
208 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
209 nvlist_add_uint64(nvl, SES_CTL_PROP_UCODE_MODE,
210 SES_DLUCODE_M_WITH_OFFS) != 0) {
211 logmsg(MSG_ERROR,
212 gettext("%s: Unable to allocate "
213 "space for device prop list\n"),
214 flashdev->drvname);
215 return (FWFLASH_FAILURE);
216 }
217
218 fprintf(stdout, "\n"); /* get a fresh line for progress updates */
219
220 if (nvlist_add_uint64(nvl, SES_CTL_PROP_UCODE_BUFID,
221 verifier->flashbuf) != 0) {
222 logmsg(MSG_ERROR,
223 gettext("%s: Unable to add buffer id "
224 "property, hence unable to flash device\n"),
225 flashdev->drvname);
226 goto cancel;
227 }
228
229 if (nvlist_add_byte_array(nvl, SES_CTL_PROP_UCODE_DATA,
230 (uint8_t *)verifier->fwimage, verifier->imgsize) != 0) {
231 logmsg(MSG_ERROR,
232 "%s: Out of memory for property addition\n",
233 flashdev->drvname);
234 goto cancel;
235 }
236
237 if ((ses_target =
238 ses_open(LIBSES_VERSION, flashdev->access_devname)) == NULL) {
239 logmsg(MSG_ERROR,
240 gettext("%s: Unable to open flashable device %s\n"),
241 flashdev->drvname, flashdev->access_devname);
242 goto cancel;
243 }
244
245 snapshot = ses_snap_hold(ses_target);
246
247 if ((targetnode = ses_snap_primary_enclosure(snapshot)) == NULL) {
248 logmsg(MSG_ERROR,
249 gettext("%s: Unable to locate primary enclosure for "
250 "device %s\n"),
251 flashdev->access_devname);
252 } else {
253 rv = sendimg(targetnode, nvl);
254 if (rv == FWFLASH_SUCCESS) {
255 logmsg(MSG_ERROR,
256 gettext("%s: Done. New image will be active "
257 "after the system is rebooted.\n\n"),
258 flashdev->drvname);
259 } else {
260 logmsg(MSG_INFO,
261 "%s: unable to flash image %s to device %s\n\n",
262 flashdev->drvname, verifier->imgfile,
263 flashdev->access_devname);
264 }
265 }
266
267 ses_snap_rele(snapshot);
268 ses_close(ses_target);
269 cancel:
270 nvlist_free(nvl);
271
272 return (rv);
273 }
274
275
276 /*
277 * The fw_identify() function walks the device
278 * tree trying to find devices which this plugin
279 * can work with.
280 *
281 * The parameter "start" gives us the starting index number
282 * to give the device when we add it to the fw_devices list.
283 *
284 * firstdev is allocated by us and we add space as needed
285 */
286 int
fw_identify(int start)287 fw_identify(int start)
288 {
289
290 int rv = FWFLASH_FAILURE;
291 di_node_t thisnode;
292 struct devicelist *newdev;
293 char *devpath;
294 char *devsuffix;
295 char *driver;
296 int idx = start;
297 size_t devlength = 0;
298 nvlist_t *props;
299 ses_snap_t *snapshot;
300 ses_node_t *rootnodep, *nodep;
301
302
303 if (strcmp(self->drvname, "sgen") == 0) {
304 devsuffix = sgensuffix;
305 driver = self->drvname;
306 } else {
307 devsuffix = sessuffix;
308 driver = drivername;
309 }
310
311 thisnode = di_drv_first_node(driver, rootnode);
312
313 if (thisnode == DI_NODE_NIL) {
314 logmsg(MSG_INFO, gettext("No %s nodes in this system\n"),
315 driver);
316 return (FWFLASH_FAILURE);
317 }
318
319 if ((devpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
320 logmsg(MSG_ERROR,
321 gettext("%s: Unable to allocate space "
322 "for a device node\n"),
323 driver);
324 return (FWFLASH_FAILURE);
325 }
326
327 /* we've found one, at least */
328
329 for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) {
330
331 devpath = di_devfs_path(thisnode);
332
333 if ((newdev = calloc(1, sizeof (struct devicelist)))
334 == NULL) {
335 logmsg(MSG_ERROR,
336 gettext("%s: identification function unable "
337 "to allocate space for device entry\n"),
338 driver);
339 free(devpath);
340 return (FWFLASH_FAILURE);
341 }
342
343 /* calloc enough for /devices + devpath + devsuffix + '\0' */
344 devlength = strlen(devpath) + strlen(devprefix) +
345 strlen(devsuffix) + 2;
346
347 if ((newdev->access_devname = calloc(1, devlength)) == NULL) {
348 logmsg(MSG_ERROR,
349 gettext("%s: Unable to allocate "
350 "space for a devfs name\n"),
351 driver);
352 free(devpath);
353 free(newdev);
354 return (FWFLASH_FAILURE);
355 }
356 snprintf(newdev->access_devname, devlength,
357 "%s%s%s", devprefix, devpath, devsuffix);
358
359 if ((newdev->drvname = calloc(1, strlen(driver) + 1))
360 == NULL) {
361 logmsg(MSG_ERROR,
362 gettext("%s: Unable to allocate "
363 "space to store a driver name\n"),
364 driver);
365 free(newdev->access_devname);
366 free(newdev);
367 free(devpath);
368 return (FWFLASH_FAILURE);
369 }
370 (void) strlcpy(newdev->drvname, driver,
371 strlen(driver) + 1);
372
373 if ((newdev->classname = calloc(1, strlen(driver) + 1))
374 == NULL) {
375 logmsg(MSG_ERROR,
376 gettext("%s: Unable to malloc "
377 "space for a class name\n"),
378 drivername);
379 free(newdev->access_devname);
380 free(newdev->drvname);
381 free(newdev);
382 free(devpath);
383 return (FWFLASH_FAILURE);
384 }
385 (void) strlcpy(newdev->classname, driver,
386 strlen(driver) + 1);
387
388 /*
389 * Only alloc as much as we truly need, and DON'T forget
390 * that libnvpair manages the memory for property lookups!
391 * The same goes for libdevinfo properties.
392 *
393 * Also note that we're allocating here before we try to
394 * ses_open() the target, because if we can't allocate
395 * sufficient space then we might as well go home.
396 */
397 newdev->ident = calloc(1, VIDLEN + PIDLEN + REVLEN + 3);
398 if (newdev->ident == NULL) {
399 logmsg(MSG_ERROR,
400 gettext("%s: Unable to malloc space for"
401 "SCSI INQUIRY data\n"), driver);
402 free(newdev->classname);
403 free(newdev->drvname);
404 free(newdev->access_devname);
405 free(newdev);
406 free(devpath);
407 return (FWFLASH_FAILURE);
408 }
409
410 if ((ses_target =
411 ses_open(LIBSES_VERSION, newdev->access_devname))
412 == NULL) {
413 logmsg(MSG_INFO,
414 gettext("%s: Unable to open device %s\n"),
415 driver, newdev->access_devname);
416 free(newdev->ident);
417 free(newdev->classname);
418 free(newdev->access_devname);
419 free(newdev->drvname);
420 free(newdev);
421 free(devpath);
422 continue;
423 }
424 snapshot = ses_snap_hold(ses_target);
425 rootnodep = ses_root_node(snapshot);
426
427 /*
428 * If the node has no properties, or the INQUIRY properties
429 * don't exist, this device does not comply with SES2 so we
430 * won't touch it.
431 */
432 if ((props = ses_node_props(rootnodep)) == NULL) {
433 free(newdev->ident);
434 ses_snap_rele(snapshot);
435 ses_close(ses_target);
436 free(newdev->classname);
437 free(newdev->access_devname);
438 free(newdev->drvname);
439 free(newdev);
440 free(devpath);
441 continue;
442 }
443
444 if ((nvlist_lookup_string(props, SCSI_PROP_VENDOR,
445 &newdev->ident->vid) != 0) ||
446 (nvlist_lookup_string(props, SCSI_PROP_PRODUCT,
447 &newdev->ident->pid) != 0) ||
448 (nvlist_lookup_string(props, SCSI_PROP_REVISION,
449 &newdev->ident->revid) != 0)) {
450 free(newdev->ident);
451 ses_snap_rele(snapshot);
452 ses_close(ses_target);
453 free(newdev->classname);
454 free(newdev->access_devname);
455 free(newdev->drvname);
456 free(newdev);
457 free(devpath);
458 continue;
459 }
460
461 nodep = ses_snap_primary_enclosure(snapshot);
462
463 if ((props = ses_node_props(nodep)) == NULL) {
464 free(newdev->ident);
465 ses_snap_rele(snapshot);
466 ses_close(ses_target);
467 free(newdev->classname);
468 free(newdev->access_devname);
469 free(newdev->drvname);
470 free(newdev);
471 free(devpath);
472 continue;
473 }
474
475 logmsg(MSG_INFO,
476 "\nvid: %s\npid: %s\nrevid: %s\n",
477 newdev->ident->vid,
478 newdev->ident->pid,
479 newdev->ident->revid);
480
481 if (nvlist_lookup_string(props, LIBSES_EN_PROP_CSN,
482 &newdev->addresses[0]) == 0) {
483 logmsg(MSG_INFO,
484 "Chassis Serial Number: %s\n",
485 newdev->addresses[0]);
486 } else
487 logmsg(MSG_INFO,
488 "%s: no chassis-serial-number property "
489 "for device %s\n",
490 driver, newdev->access_devname);
491
492
493 rv = di_prop_lookup_strings(DDI_DEV_T_ANY,
494 thisnode, "target-port", &newdev->addresses[1]);
495 if (rv < 0) {
496 logmsg(MSG_INFO,
497 "%s: no target-port property "
498 "for device %s\n",
499 driver, newdev->access_devname);
500 } else
501 logmsg(MSG_INFO,
502 "target-port property: %s\n",
503 newdev->addresses[1]);
504
505
506 newdev->index = idx;
507 ++idx;
508 newdev->plugin = self;
509
510 ses_snap_rele(snapshot);
511 TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev);
512 }
513
514
515 if (fwflash_debug != 0) {
516 struct devicelist *tempdev;
517
518 TAILQ_FOREACH(tempdev, fw_devices, nextdev) {
519 logmsg(MSG_INFO, "%s:fw_identify:\n",
520 driver);
521 logmsg(MSG_INFO,
522 "\ttempdev @ 0x%lx\n"
523 "\t\taccess_devname: %s\n"
524 "\t\tdrvname: %s\tclassname: %s\n"
525 "\t\tident->vid: %s\n"
526 "\t\tident->pid: %s\n"
527 "\t\tident->revid: %s\n"
528 "\t\tindex: %d\n"
529 "\t\taddress[0]: %s\n"
530 "\t\taddress[1]: %s\n"
531 "\t\tplugin @ 0x%lx\n\n",
532 &tempdev,
533 tempdev->access_devname,
534 tempdev->drvname, newdev->classname,
535 tempdev->ident->vid,
536 tempdev->ident->pid,
537 tempdev->ident->revid,
538 tempdev->index,
539 (tempdev->addresses[0] ? tempdev->addresses[0] :
540 "(not supported)"),
541 (tempdev->addresses[1] ? tempdev->addresses[1] :
542 "(not supported)"),
543 &tempdev->plugin);
544 }
545 }
546
547 return (FWFLASH_SUCCESS);
548 }
549
550
551
552 int
fw_devinfo(struct devicelist * thisdev)553 fw_devinfo(struct devicelist *thisdev)
554 {
555
556 fprintf(stdout, gettext("Device[%d] %s\n Class [%s]\n"),
557 thisdev->index, thisdev->access_devname, thisdev->classname);
558
559 fprintf(stdout,
560 gettext("\tVendor : %s\n"
561 "\tProduct : %s\n"
562 "\tFirmware revision : %s\n"
563 "\tChassis Serial Number : %s\n"
564 "\tTarget-port identifier : %s\n"),
565 thisdev->ident->vid,
566 thisdev->ident->pid,
567 thisdev->ident->revid,
568 (thisdev->addresses[0] ? thisdev->addresses[0] :
569 "(not supported)"),
570 (thisdev->addresses[1] ? thisdev->addresses[1] :
571 "(not supported)"));
572
573 fprintf(stdout, "\n\n");
574
575 return (FWFLASH_SUCCESS);
576 }
577
578
579
580
581
582 /*ARGSUSED*/
583 static int
get_status(nvlist_t * props,ucode_status_t * sp)584 get_status(nvlist_t *props, ucode_status_t *sp)
585 {
586 int i;
587 uint64_t status, astatus;
588
589 if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE, &status) != 0) {
590 sp->us_status = -1ULL;
591 (void) snprintf(sp->us_desc, sizeof (sp->us_desc),
592 "not supported");
593 return (FWFLASH_FAILURE);
594 }
595
596 if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE_A,
597 &astatus) != 0) {
598 logmsg(MSG_ERROR,
599 gettext("\nError: Unable to retrieve current status\n"));
600 return (FWFLASH_FAILURE);
601 }
602
603 for (i = 0; i < NUCODE_STATUS; i++) {
604 if (ucode_statdesc_table[i].us_value == status)
605 break;
606 }
607
608 sp->us_status = status;
609
610 if (i == NUCODE_STATUS) {
611 (void) snprintf(sp->us_desc, sizeof (sp->us_desc),
612 "unknown (0x%02x)", (int)status);
613 sp->us_iserr = sp->us_pending = B_TRUE;
614 return (FWFLASH_FAILURE);
615 } else {
616 /* LINTED */
617 (void) snprintf(sp->us_desc, sizeof (sp->us_desc),
618 ucode_statdesc_table[i].us_desc, (int)astatus);
619 sp->us_iserr = ucode_statdesc_table[i].us_iserr;
620 sp->us_pending = ucode_statdesc_table[i].us_pending;
621 }
622
623 return (FWFLASH_SUCCESS);
624 }
625
626
627 static int
print_updated_status(ses_node_t * np,void * arg)628 print_updated_status(ses_node_t *np, void *arg)
629 {
630 ucode_wait_t *uwp = arg;
631 nvlist_t *props;
632 ucode_status_t status;
633
634
635 if ((props = ses_node_props(np)) == NULL) {
636 return (FWFLASH_FAILURE);
637 }
638
639 if (get_status(props, &status) != FWFLASH_SUCCESS)
640 return (FWFLASH_FAILURE);
641
642 if (status.us_status != uwp->uw_prevstatus)
643 (void) printf("%30s: %s\n", "status", status.us_desc);
644
645 uwp->uw_prevstatus = status.us_status;
646 uwp->uw_pending = status.us_pending;
647
648 if (status.us_iserr) {
649 logmsg(MSG_INFO,
650 "libses: status.us_iserr: 0x%0x\n",
651 status.us_iserr);
652 return (FWFLASH_FAILURE);
653 }
654 return (FWFLASH_SUCCESS);
655 }
656
657 /*ARGSUSED*/
658 static int
sendimg(ses_node_t * np,void * data)659 sendimg(ses_node_t *np, void *data)
660 {
661 nvlist_t *props;
662 nvlist_t *arg = data;
663 char *vendor, *product, *revision, *csn;
664 char buf[128];
665 ses_snap_t *newsnap;
666 int ret;
667 ucode_status_t statdesc;
668 ucode_wait_t wait;
669 uint8_t *imagedata;
670 uint_t len;
671
672
673 /* If we've been called without data, eject */
674 if (nvlist_lookup_byte_array(arg, SES_CTL_PROP_UCODE_DATA,
675 &imagedata, &len) != 0) {
676 return (FWFLASH_FAILURE);
677 }
678
679 props = ses_node_props(np);
680 if ((props == NULL) ||
681 (nvlist_lookup_string(props, SES_EN_PROP_VID, &vendor) != 0) ||
682 (nvlist_lookup_string(props, SES_EN_PROP_PID, &product) != 0) ||
683 (nvlist_lookup_string(props, SES_EN_PROP_REV, &revision) != 0) ||
684 (nvlist_lookup_string(props, LIBSES_EN_PROP_CSN, &csn) != 0)) {
685 return (FWFLASH_FAILURE);
686 }
687
688 (void) printf("%30s: %s\n", "vendor", vendor);
689 (void) printf("%30s: %s\n", "product", product);
690 (void) printf("%30s: %s\n", "revision", revision);
691 (void) printf("%30s: %s\n", "serial", csn);
692
693 ret = get_status(props, &statdesc);
694 (void) printf("%30s: %s\n", "current status", statdesc.us_desc);
695 if (ret != FWFLASH_SUCCESS) {
696 return (FWFLASH_FAILURE);
697 }
698
699 (void) snprintf(buf, sizeof (buf), "downloading %u bytes", len);
700 (void) printf("\n%30s: ", buf);
701
702 /*
703 * If the bufferid isn't 2, then the verifier has already
704 * OK'd the image that the user has provided.
705 *
706 * At present the non-"standard" images need to be flashed
707 * using the scsi WRITE BUFFER command
708 */
709 if (verifier->flashbuf != 2)
710 return (scsi_writebuf());
711
712
713 if (ses_node_ctl(np, SES_CTL_OP_DL_UCODE, arg) != FWFLASH_SUCCESS) {
714 (void) printf("failed!\n");
715 (void) printf("%s\n", ses_errmsg());
716 return (FWFLASH_FAILURE);
717 } else {
718 (void) printf("ok\n");
719 }
720
721 wait.uw_prevstatus = -1ULL;
722 wait.uw_oldnp = np;
723
724 if ((newsnap = ses_snap_new(ses_target)) == NULL) {
725 logmsg(MSG_ERROR,
726 "failed to update SES snapshot: %s",
727 ses_errmsg());
728 return (FWFLASH_FAILURE);
729 }
730
731 print_updated_status(ses_snap_primary_enclosure(newsnap),
732 &wait);
733 ses_snap_rele(newsnap);
734
735 return (FWFLASH_SUCCESS);
736 }
737
738 static int
scsi_writebuf()739 scsi_writebuf()
740 {
741 int ret;
742 int i = 0;
743 libscsi_action_t *action;
744 spc3_write_buffer_cdb_t *wb_cdb;
745 libscsi_hdl_t *handle;
746 libscsi_target_t *target;
747 sam4_status_t samstatus;
748
749
750 target = ses_scsi_target(ses_target);
751 handle = libscsi_get_handle(target);
752 action = libscsi_action_alloc(handle, SPC3_CMD_WRITE_BUFFER,
753 LIBSCSI_AF_WRITE|LIBSCSI_AF_RQSENSE,
754 (void *)verifier->fwimage, (size_t)verifier->imgsize);
755
756 wb_cdb = (spc3_write_buffer_cdb_t *)libscsi_action_get_cdb(action);
757
758 wb_cdb->wbc_mode = SPC3_WB_MODE_DATA;
759 wb_cdb->wbc_bufferid = verifier->flashbuf;
760
761 wb_cdb->wbc_buffer_offset[0] = 0;
762 wb_cdb->wbc_buffer_offset[1] = 0;
763 wb_cdb->wbc_buffer_offset[2] = 0;
764
765 wb_cdb->wbc_parameter_list_len[0] =
766 (verifier->imgsize & 0xff0000) >> 16;
767 wb_cdb->wbc_parameter_list_len[1] = (verifier->imgsize & 0xff00) >> 8;
768 wb_cdb->wbc_parameter_list_len[2] = (verifier->imgsize & 0xff);
769
770 ret = libscsi_exec(action, target);
771 samstatus = libscsi_action_get_status(action);
772
773 logmsg(MSG_INFO,
774 "\nscsi_writebuffer: ret 0x%0x, samstatus 0x%0x\n",
775 ret, samstatus);
776
777 if ((ret != FWFLASH_SUCCESS) || samstatus != SAM4_STATUS_GOOD) {
778 libscsi_action_free(action);
779 return (FWFLASH_FAILURE);
780 } else {
781 (void) printf("ok\n");
782 }
783
784 for (i = 0; i < NSAM4_STATUS; i++) {
785 if (sam4_status[i].status == samstatus) {
786 (void) printf("%s\n", (sam4_status[i].message));
787 break;
788 }
789 }
790
791 if (i == NSAM4_STATUS)
792 (void) printf("Status: UNKNOWN\n");
793
794 if (samstatus == SAM4_STATUS_GOOD) {
795 return (FWFLASH_SUCCESS);
796 }
797
798 return (FWFLASH_FAILURE);
799 }
800