xref: /onnv-gate/usr/src/uts/common/io/scsi/impl/scsi_fm.c (revision 12213:f49a344d4308)
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