17570SDavid.Zhang@Sun.COM /*
27570SDavid.Zhang@Sun.COM * CDDL HEADER START
37570SDavid.Zhang@Sun.COM *
47570SDavid.Zhang@Sun.COM * The contents of this file are subject to the terms of the
57570SDavid.Zhang@Sun.COM * Common Development and Distribution License (the "License").
67570SDavid.Zhang@Sun.COM * You may not use this file except in compliance with the License.
77570SDavid.Zhang@Sun.COM *
87570SDavid.Zhang@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97570SDavid.Zhang@Sun.COM * or http://www.opensolaris.org/os/licensing.
107570SDavid.Zhang@Sun.COM * See the License for the specific language governing permissions
117570SDavid.Zhang@Sun.COM * and limitations under the License.
127570SDavid.Zhang@Sun.COM *
137570SDavid.Zhang@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147570SDavid.Zhang@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157570SDavid.Zhang@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167570SDavid.Zhang@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177570SDavid.Zhang@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187570SDavid.Zhang@Sun.COM *
197570SDavid.Zhang@Sun.COM * CDDL HEADER END
207570SDavid.Zhang@Sun.COM */
217570SDavid.Zhang@Sun.COM /*
22*12213SGavin.Maltby@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
237570SDavid.Zhang@Sun.COM */
247570SDavid.Zhang@Sun.COM
257570SDavid.Zhang@Sun.COM /*
267570SDavid.Zhang@Sun.COM * SCSI FMA implementation
277570SDavid.Zhang@Sun.COM */
287570SDavid.Zhang@Sun.COM
297570SDavid.Zhang@Sun.COM #include <sys/scsi/scsi_types.h>
307570SDavid.Zhang@Sun.COM #include <sys/sunmdi.h>
317570SDavid.Zhang@Sun.COM #include <sys/va_list.h>
327570SDavid.Zhang@Sun.COM
337570SDavid.Zhang@Sun.COM #include <sys/ddi_impldefs.h>
347570SDavid.Zhang@Sun.COM
357570SDavid.Zhang@Sun.COM /* consolidation private interface to generate dev scheme ereport */
367570SDavid.Zhang@Sun.COM extern void fm_dev_ereport_postv(dev_info_t *dip, dev_info_t *eqdip,
377570SDavid.Zhang@Sun.COM const char *devpath, const char *minor_name, const char *devid,
38*12213SGavin.Maltby@Sun.COM const char *tpl0, const char *error_class, uint64_t ena, int sflag,
39*12213SGavin.Maltby@Sun.COM nvlist_t *, va_list ap);
407570SDavid.Zhang@Sun.COM extern char *mdi_pi_pathname_by_instance(int);
417570SDavid.Zhang@Sun.COM
427570SDavid.Zhang@Sun.COM #define FM_SCSI_CLASS "scsi"
437570SDavid.Zhang@Sun.COM #define ERPT_CLASS_SZ sizeof (FM_SCSI_CLASS) + 1 + DDI_MAX_ERPT_CLASS + 1
447570SDavid.Zhang@Sun.COM
457570SDavid.Zhang@Sun.COM /*
467570SDavid.Zhang@Sun.COM * scsi_fm_init: Initialize fma capabilities and register with IO
477570SDavid.Zhang@Sun.COM * fault services.
487570SDavid.Zhang@Sun.COM */
497570SDavid.Zhang@Sun.COM void
scsi_fm_init(struct scsi_device * sd)507570SDavid.Zhang@Sun.COM scsi_fm_init(struct scsi_device *sd)
517570SDavid.Zhang@Sun.COM {
527570SDavid.Zhang@Sun.COM dev_info_t *dip = sd->sd_dev;
537570SDavid.Zhang@Sun.COM
547570SDavid.Zhang@Sun.COM /*
557570SDavid.Zhang@Sun.COM * fm-capable in driver.conf can be used to set fm_capabilities.
567570SDavid.Zhang@Sun.COM * If fm-capable is not defined, then the last argument passed to
577570SDavid.Zhang@Sun.COM * ddi_prop_get_int will be returned as the capabilities.
587570SDavid.Zhang@Sun.COM *
597570SDavid.Zhang@Sun.COM * NOTE: by default scsi_fm_capable sets DDI_FM_EREPORT_CAPABLE.
607570SDavid.Zhang@Sun.COM */
617570SDavid.Zhang@Sun.COM sd->sd_fm_capable = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
627570SDavid.Zhang@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fm-capable",
637570SDavid.Zhang@Sun.COM scsi_fm_capable);
647570SDavid.Zhang@Sun.COM
657570SDavid.Zhang@Sun.COM /*
667570SDavid.Zhang@Sun.COM * Register capabilities with IO Fault Services. The capabilities
677570SDavid.Zhang@Sun.COM * set above may not be supported by the parent nexus, in that
687570SDavid.Zhang@Sun.COM * case some/all capability bits may be cleared.
697570SDavid.Zhang@Sun.COM *
707570SDavid.Zhang@Sun.COM * NOTE: iblock cookies are not important because scsi HBAs
717570SDavid.Zhang@Sun.COM * always interrupt below LOCK_LEVEL.
727570SDavid.Zhang@Sun.COM */
737570SDavid.Zhang@Sun.COM if (sd->sd_fm_capable != DDI_FM_NOT_CAPABLE)
747570SDavid.Zhang@Sun.COM ddi_fm_init(dip, &sd->sd_fm_capable, NULL);
757570SDavid.Zhang@Sun.COM }
767570SDavid.Zhang@Sun.COM
777570SDavid.Zhang@Sun.COM /*
787570SDavid.Zhang@Sun.COM * scsi_fm_fini: un-register with IO fault services.
797570SDavid.Zhang@Sun.COM */
807570SDavid.Zhang@Sun.COM void
scsi_fm_fini(struct scsi_device * sd)817570SDavid.Zhang@Sun.COM scsi_fm_fini(struct scsi_device *sd)
827570SDavid.Zhang@Sun.COM {
837570SDavid.Zhang@Sun.COM dev_info_t *dip = sd->sd_dev;
847570SDavid.Zhang@Sun.COM
857570SDavid.Zhang@Sun.COM if (sd->sd_fm_capable != DDI_FM_NOT_CAPABLE)
867570SDavid.Zhang@Sun.COM ddi_fm_fini(dip);
877570SDavid.Zhang@Sun.COM }
887570SDavid.Zhang@Sun.COM
897570SDavid.Zhang@Sun.COM /*
907570SDavid.Zhang@Sun.COM *
91*12213SGavin.Maltby@Sun.COM * scsi_fm_ereport_post - Post an ereport
927570SDavid.Zhang@Sun.COM */
937570SDavid.Zhang@Sun.COM void
scsi_fm_ereport_post(struct scsi_device * sd,int path_instance,char * devpath,const char * error_class,uint64_t ena,char * devid,char * tpl0,int sflag,nvlist_t * pl,...)947570SDavid.Zhang@Sun.COM scsi_fm_ereport_post(struct scsi_device *sd, int path_instance,
95*12213SGavin.Maltby@Sun.COM char *devpath, const char *error_class, uint64_t ena,
96*12213SGavin.Maltby@Sun.COM char *devid, char *tpl0, int sflag, nvlist_t *pl, ...)
977570SDavid.Zhang@Sun.COM {
987570SDavid.Zhang@Sun.COM char class[ERPT_CLASS_SZ];
997570SDavid.Zhang@Sun.COM dev_info_t *dip = sd->sd_dev;
100*12213SGavin.Maltby@Sun.COM dev_info_t *eqdip = dip;
101*12213SGavin.Maltby@Sun.COM char *minor_name;
1027570SDavid.Zhang@Sun.COM va_list ap;
1037570SDavid.Zhang@Sun.COM
104*12213SGavin.Maltby@Sun.COM /*
105*12213SGavin.Maltby@Sun.COM * If the scsi_device eqdip is not yet ereport capable, send the
106*12213SGavin.Maltby@Sun.COM * report based on parent capabilities. This is needed for
107*12213SGavin.Maltby@Sun.COM * telemetry during enumeration.
108*12213SGavin.Maltby@Sun.COM */
109*12213SGavin.Maltby@Sun.COM if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(eqdip)))
110*12213SGavin.Maltby@Sun.COM eqdip = ddi_get_parent(eqdip);
111*12213SGavin.Maltby@Sun.COM
1127570SDavid.Zhang@Sun.COM /* Add "scsi." as a prefix to the class */
1137570SDavid.Zhang@Sun.COM (void) snprintf(class, ERPT_CLASS_SZ, "%s.%s",
1147570SDavid.Zhang@Sun.COM FM_SCSI_CLASS, error_class);
1157570SDavid.Zhang@Sun.COM
1167570SDavid.Zhang@Sun.COM /*
117*12213SGavin.Maltby@Sun.COM * Get the path:
118*12213SGavin.Maltby@Sun.COM *
119*12213SGavin.Maltby@Sun.COM * If path_instance is non-zero then the packet was
1207570SDavid.Zhang@Sun.COM * sent to scsi_vhci. We return the pathinfo path_string associated
1217570SDavid.Zhang@Sun.COM * with the path_instance path - which refers to the actual hardware.
122*12213SGavin.Maltby@Sun.COM *
123*12213SGavin.Maltby@Sun.COM * If path_instance is zero then use the devpath provided by the
124*12213SGavin.Maltby@Sun.COM * caller; if it was NULL then this will cause fm_dev_ereport_post
125*12213SGavin.Maltby@Sun.COM * to use the devinfo path of the first devi we pass to it, ie
126*12213SGavin.Maltby@Sun.COM * sd->sd_dev.
1277570SDavid.Zhang@Sun.COM */
1287570SDavid.Zhang@Sun.COM if (path_instance)
1297570SDavid.Zhang@Sun.COM devpath = mdi_pi_pathname_by_instance(path_instance);
1307570SDavid.Zhang@Sun.COM
1317570SDavid.Zhang@Sun.COM /*
1327570SDavid.Zhang@Sun.COM * Set the minor_name to NULL. The block location of a media error
1337570SDavid.Zhang@Sun.COM * is described by the 'lba' property. We use the 'lba' instead of
1347570SDavid.Zhang@Sun.COM * the partition (minor_name) because the defect stays in the same
1357570SDavid.Zhang@Sun.COM * place even when a repartition operation may result in the defect
1367570SDavid.Zhang@Sun.COM * showing up in a different partition (minor_name). To support
1377570SDavid.Zhang@Sun.COM * retire at the block/partition level, the user level retire agent
1387570SDavid.Zhang@Sun.COM * should map the 'lba' to the current effected partition.
1397570SDavid.Zhang@Sun.COM */
1407570SDavid.Zhang@Sun.COM minor_name = NULL;
1417570SDavid.Zhang@Sun.COM
1427570SDavid.Zhang@Sun.COM /*
1437570SDavid.Zhang@Sun.COM * NOTE: If there is a 'linked' ena to be had, it should likely come
1447570SDavid.Zhang@Sun.COM * from the buf structure via the scsi_pkt pkt->pkt_bp.
1457570SDavid.Zhang@Sun.COM */
1467570SDavid.Zhang@Sun.COM
1477570SDavid.Zhang@Sun.COM /* Post the ereport */
148*12213SGavin.Maltby@Sun.COM va_start(ap, pl);
149*12213SGavin.Maltby@Sun.COM fm_dev_ereport_postv(dip, eqdip, devpath, minor_name, devid, tpl0,
150*12213SGavin.Maltby@Sun.COM class, ena, sflag, pl, ap);
1517570SDavid.Zhang@Sun.COM va_end(ap);
1527570SDavid.Zhang@Sun.COM }
153