xref: /illumos-gate/usr/src/uts/common/io/scsi/impl/smp_transport.c (revision 1edba515a3484e0f74b638b203d462b3112ac84d)
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 #include <sys/byteorder.h>
27 #include <sys/scsi/scsi.h>
28 
29 static int
30 smp_device_prop_update_inqstring(struct smp_device *smp_sd,
31     char *name, char *data, size_t len)
32 {
33 	int	ilen;
34 	char	*data_string;
35 	int	rv;
36 
37 	/* SMP information follows SCSI INQUIRY rules */
38 	ilen = scsi_ascii_inquiry_len(data, len);
39 	ASSERT(ilen <= (int)len);
40 	if (ilen <= 0)
41 		return (DDI_PROP_INVAL_ARG);
42 
43 	/* ensure null termination */
44 	data_string = kmem_zalloc(ilen + 1, KM_SLEEP);
45 	bcopy(data, data_string, ilen);
46 	rv = ndi_prop_update_string(DDI_DEV_T_NONE,
47 	    smp_sd->smp_sd_dev, name, data_string);
48 	kmem_free(data_string, ilen + 1);
49 	return (rv);
50 }
51 
52 /*
53  * smp_probe: probe device and create inquiry-like properties.
54  */
55 int
56 smp_probe(struct smp_device *smp_sd)
57 {
58 	smp_pkt_t				*smp_pkt;
59 	smp_pkt_t				smp_pkt_data;
60 	smp_request_frame_t			*srq;
61 	smp_response_frame_t			*srs;
62 	smp_report_manufacturer_info_resp_t	*srmir;
63 	int					ilen, clen;
64 	char					*component;
65 	uint8_t			srq_buf[SMP_REQ_MINLEN];
66 	uint8_t			srs_buf[SMP_RESP_MINLEN + sizeof (*srmir)];
67 
68 	srq = (smp_request_frame_t *)srq_buf;
69 	bzero(srq, sizeof (srq_buf));
70 	srq->srf_frame_type = SMP_FRAME_TYPE_REQUEST;
71 	srq->srf_function = SMP_FUNC_REPORT_MANUFACTURER_INFO;
72 
73 	smp_pkt = &smp_pkt_data;
74 	bzero(smp_pkt, sizeof (*smp_pkt));
75 	smp_pkt->smp_pkt_address = &smp_sd->smp_sd_address;
76 	smp_pkt->smp_pkt_req = (caddr_t)srq;
77 	smp_pkt->smp_pkt_reqsize = sizeof (srq_buf);
78 	smp_pkt->smp_pkt_rsp = (caddr_t)srs_buf;
79 	smp_pkt->smp_pkt_rspsize = sizeof (srs_buf);
80 	smp_pkt->smp_pkt_timeout = SMP_DEFAULT_TIMEOUT;
81 
82 	bzero(srs_buf, sizeof (srs_buf));
83 
84 	if (smp_transport(smp_pkt) != DDI_SUCCESS) {
85 		/*
86 		 * The EOVERFLOW should be excluded here, because it indicates
87 		 * the buffer (defined according to SAS1.1 Spec) to store
88 		 * response is shorter than transferred message frame.
89 		 * In this case, the smp device is alive and should be
90 		 * enumerated.
91 		 */
92 		if (smp_pkt->smp_pkt_reason != EOVERFLOW)
93 			return (DDI_PROBE_FAILURE);
94 	}
95 
96 	/*
97 	 * NOTE: Deal with old drivers (mpt, mpt_sas) that allocate
98 	 * 'struct smp_device' on the stack.  When these drivers convert to
99 	 * SCSAv3, the check for a NULL smp_sd_dev can be removed.
100 	 */
101 	if (smp_sd->smp_sd_dev == NULL)
102 		return (DDI_PROBE_SUCCESS);
103 
104 	/* Save raw response data for devid */
105 	srs = (smp_response_frame_t *)srs_buf;
106 	if (srs->srf_result != SMP_RES_FUNCTION_ACCEPTED)
107 		return (DDI_PROBE_SUCCESS);
108 
109 	/*
110 	 * Convert smp_report_manufacturer_info_resp_t data into properties.
111 	 * NOTE: since things show up in the oposite order in prtconf, we are
112 	 * going from detailed information to generic here.
113 	 */
114 	srmir = (smp_report_manufacturer_info_resp_t *)&srs->srf_data[0];
115 	if (srmir->srmir_sas_1_1_format) {
116 		/* Establish 'component' property. */
117 		ilen = scsi_ascii_inquiry_len(
118 		    srmir->srmir_component_vendor_identification,
119 		    sizeof (srmir->srmir_component_vendor_identification));
120 		if (ilen > 0) {
121 			/* component value format is '%s.%05d.%03d' */
122 			clen = ilen + 1 + 5 + 1 + 3 + 1;
123 			component = kmem_zalloc(clen, KM_SLEEP);
124 			bcopy(srmir->srmir_component_vendor_identification,
125 			    component, ilen);
126 			(void) snprintf(&component[ilen], clen - ilen,
127 			    ".%05d.%03d", BE_16(srmir->srmir_component_id),
128 			    srmir->srmir_component_revision_level);
129 			if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev,
130 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
131 			    "component") == 0)
132 				(void) ndi_prop_update_string(DDI_DEV_T_NONE,
133 				    smp_sd->smp_sd_dev, "component", component);
134 			kmem_free(component, clen);
135 		}
136 	}
137 	/* First one to define the property wins */
138 	if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev,
139 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_REVISION_ID) == 0)
140 		(void) smp_device_prop_update_inqstring(smp_sd,
141 		    INQUIRY_REVISION_ID, srmir->srmir_product_revision_level,
142 		    sizeof (srmir->srmir_product_revision_level));
143 
144 	if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev,
145 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_PRODUCT_ID) == 0)
146 		(void) smp_device_prop_update_inqstring(smp_sd,
147 		    INQUIRY_PRODUCT_ID, srmir->srmir_product_identification,
148 		    sizeof (srmir->srmir_product_identification));
149 
150 	if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev,
151 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_VENDOR_ID) == 0)
152 		(void) smp_device_prop_update_inqstring(smp_sd,
153 		    INQUIRY_VENDOR_ID, srmir->srmir_vendor_identification,
154 		    sizeof (srmir->srmir_vendor_identification));
155 
156 	/* NOTE: SMP_PROP_REPORT_MANUFACTURER is deleted after devid created */
157 	if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev,
158 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
159 	    SMP_PROP_REPORT_MANUFACTURER) == 0)
160 		(void) ndi_prop_update_byte_array(DDI_DEV_T_NONE,
161 		    smp_sd->smp_sd_dev, SMP_PROP_REPORT_MANUFACTURER,
162 		    (uchar_t *)srs, sizeof (srs_buf));
163 
164 	return (DDI_PROBE_SUCCESS);
165 }
166 
167 int
168 smp_transport(struct smp_pkt *smp_pkt)
169 {
170 	return (smp_pkt->smp_pkt_address->
171 	    smp_a_hba_tran->smp_tran_start(smp_pkt));
172 }
173