1*b8aa3defSJoshua M. Clulow /*
2*b8aa3defSJoshua M. Clulow  * This file and its contents are supplied under the terms of the
3*b8aa3defSJoshua M. Clulow  * Common Development and Distribution License ("CDDL"), version 1.0.
4*b8aa3defSJoshua M. Clulow  * You may only use this file in accordance with the terms of version
5*b8aa3defSJoshua M. Clulow  * 1.0 of the CDDL.
6*b8aa3defSJoshua M. Clulow  *
7*b8aa3defSJoshua M. Clulow  * A full copy of the text of the CDDL should have accompanied this
8*b8aa3defSJoshua M. Clulow  * source.  A copy of the CDDL is also available via the Internet at
9*b8aa3defSJoshua M. Clulow  * http://www.illumos.org/license/CDDL.
10*b8aa3defSJoshua M. Clulow  */
11*b8aa3defSJoshua M. Clulow 
12*b8aa3defSJoshua M. Clulow /*
13*b8aa3defSJoshua M. Clulow  * Copyright 2017 Joyent, Inc.
14*b8aa3defSJoshua M. Clulow  */
15*b8aa3defSJoshua M. Clulow 
16*b8aa3defSJoshua M. Clulow /*
17*b8aa3defSJoshua M. Clulow  * Collection of routines specific to SATA devices and attempting to make them
18*b8aa3defSJoshua M. Clulow  * work.
19*b8aa3defSJoshua M. Clulow  */
20*b8aa3defSJoshua M. Clulow 
21*b8aa3defSJoshua M. Clulow #include <sys/scsi/adapters/smrt/smrt.h>
22*b8aa3defSJoshua M. Clulow 
23*b8aa3defSJoshua M. Clulow /*
24*b8aa3defSJoshua M. Clulow  * This is a buffer size that should easily cover all of the data that we need
25*b8aa3defSJoshua M. Clulow  * to properly determine the buffer allocation.
26*b8aa3defSJoshua M. Clulow  */
27*b8aa3defSJoshua M. Clulow #define	SMRT_SATA_INQ83_LEN	256
28*b8aa3defSJoshua M. Clulow 
29*b8aa3defSJoshua M. Clulow /*
30*b8aa3defSJoshua M. Clulow  * We need to try and determine if a SATA WWN exists on the device.  SAT-2
31*b8aa3defSJoshua M. Clulow  * defines that the response to the inquiry page 0x83.
32*b8aa3defSJoshua M. Clulow  */
33*b8aa3defSJoshua M. Clulow int
smrt_sata_determine_wwn(smrt_t * smrt,PhysDevAddr_t * addr,uint64_t * wwnp,uint16_t timeout)34*b8aa3defSJoshua M. Clulow smrt_sata_determine_wwn(smrt_t *smrt, PhysDevAddr_t *addr, uint64_t *wwnp,
35*b8aa3defSJoshua M. Clulow     uint16_t timeout)
36*b8aa3defSJoshua M. Clulow {
37*b8aa3defSJoshua M. Clulow 	smrt_command_t *smcm;
38*b8aa3defSJoshua M. Clulow 	int r;
39*b8aa3defSJoshua M. Clulow 	uint8_t *inq;
40*b8aa3defSJoshua M. Clulow 	uint64_t wwn;
41*b8aa3defSJoshua M. Clulow 	size_t resid;
42*b8aa3defSJoshua M. Clulow 
43*b8aa3defSJoshua M. Clulow 	VERIFY3P(wwnp, !=, NULL);
44*b8aa3defSJoshua M. Clulow 
45*b8aa3defSJoshua M. Clulow 	if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
46*b8aa3defSJoshua M. Clulow 	    KM_NOSLEEP)) == NULL || smrt_command_attach_internal(smrt, smcm,
47*b8aa3defSJoshua M. Clulow 	    SMRT_SATA_INQ83_LEN, KM_NOSLEEP) != 0) {
48*b8aa3defSJoshua M. Clulow 		if (smcm != NULL) {
49*b8aa3defSJoshua M. Clulow 			smrt_command_free(smcm);
50*b8aa3defSJoshua M. Clulow 		}
51*b8aa3defSJoshua M. Clulow 		return (ENOMEM);
52*b8aa3defSJoshua M. Clulow 	}
53*b8aa3defSJoshua M. Clulow 
54*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Header.LUN.PhysDev = *addr;
55*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDBLen = CDB_GROUP0;
56*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
57*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
58*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_READ;
59*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Timeout = LE_16(timeout);
60*b8aa3defSJoshua M. Clulow 
61*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDB[0] = SCMD_INQUIRY;
62*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDB[1] = 1;
63*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDB[2] = 0x83;
64*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDB[3] = (SMRT_SATA_INQ83_LEN & 0xff00) >> 8;
65*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDB[4] = SMRT_SATA_INQ83_LEN & 0x00ff;
66*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDB[5] = 0;
67*b8aa3defSJoshua M. Clulow 
68*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
69*b8aa3defSJoshua M. Clulow 
70*b8aa3defSJoshua M. Clulow 	/*
71*b8aa3defSJoshua M. Clulow 	 * Send the command to the device.
72*b8aa3defSJoshua M. Clulow 	 */
73*b8aa3defSJoshua M. Clulow 	smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
74*b8aa3defSJoshua M. Clulow 	if ((r = smrt_submit(smrt, smcm)) != 0) {
75*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
76*b8aa3defSJoshua M. Clulow 		smrt_command_free(smcm);
77*b8aa3defSJoshua M. Clulow 		return (r);
78*b8aa3defSJoshua M. Clulow 	}
79*b8aa3defSJoshua M. Clulow 
80*b8aa3defSJoshua M. Clulow 	if ((r = smrt_poll_for(smrt, smcm)) != 0) {
81*b8aa3defSJoshua M. Clulow 		VERIFY3S(r, ==, ETIMEDOUT);
82*b8aa3defSJoshua M. Clulow 		VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
83*b8aa3defSJoshua M. Clulow 
84*b8aa3defSJoshua M. Clulow 		/*
85*b8aa3defSJoshua M. Clulow 		 * The command timed out; abandon it now.  Remove the POLLED
86*b8aa3defSJoshua M. Clulow 		 * flag so that the periodic routine will send an abort to
87*b8aa3defSJoshua M. Clulow 		 * clean it up next time around.
88*b8aa3defSJoshua M. Clulow 		 */
89*b8aa3defSJoshua M. Clulow 		smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
90*b8aa3defSJoshua M. Clulow 		smcm->smcm_status &= ~SMRT_CMD_STATUS_POLLED;
91*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
92*b8aa3defSJoshua M. Clulow 		return (r);
93*b8aa3defSJoshua M. Clulow 	}
94*b8aa3defSJoshua M. Clulow 
95*b8aa3defSJoshua M. Clulow 	if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
96*b8aa3defSJoshua M. Clulow 		/*
97*b8aa3defSJoshua M. Clulow 		 * The controller was reset while we were trying to discover
98*b8aa3defSJoshua M. Clulow 		 * logical volumes.  Report failure.
99*b8aa3defSJoshua M. Clulow 		 */
100*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
101*b8aa3defSJoshua M. Clulow 		smrt_command_free(smcm);
102*b8aa3defSJoshua M. Clulow 		return (EIO);
103*b8aa3defSJoshua M. Clulow 	}
104*b8aa3defSJoshua M. Clulow 
105*b8aa3defSJoshua M. Clulow 	if (smcm->smcm_status & SMRT_CMD_STATUS_ERROR) {
106*b8aa3defSJoshua M. Clulow 		ErrorInfo_t *ei = smcm->smcm_va_err;
107*b8aa3defSJoshua M. Clulow 
108*b8aa3defSJoshua M. Clulow 		if (ei->CommandStatus != CISS_CMD_DATA_UNDERRUN) {
109*b8aa3defSJoshua M. Clulow 			dev_err(smrt->smrt_dip, CE_WARN, "physical target "
110*b8aa3defSJoshua M. Clulow 			    "SATA WWN error: status 0x%x", ei->CommandStatus);
111*b8aa3defSJoshua M. Clulow 			mutex_exit(&smrt->smrt_mutex);
112*b8aa3defSJoshua M. Clulow 			smrt_command_free(smcm);
113*b8aa3defSJoshua M. Clulow 			return (EIO);
114*b8aa3defSJoshua M. Clulow 		}
115*b8aa3defSJoshua M. Clulow 		resid = ei->ResidualCnt;
116*b8aa3defSJoshua M. Clulow 	} else {
117*b8aa3defSJoshua M. Clulow 		resid = 0;
118*b8aa3defSJoshua M. Clulow 	}
119*b8aa3defSJoshua M. Clulow 
120*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
121*b8aa3defSJoshua M. Clulow 
122*b8aa3defSJoshua M. Clulow 	/*
123*b8aa3defSJoshua M. Clulow 	 * We must have at least 12 bytes.  The first four bytes are the header,
124*b8aa3defSJoshua M. Clulow 	 * the next four are for the LUN header, and the last 8 are for the
125*b8aa3defSJoshua M. Clulow 	 * actual WWN, which according to SAT-2 will always be first.
126*b8aa3defSJoshua M. Clulow 	 */
127*b8aa3defSJoshua M. Clulow 	if (SMRT_SATA_INQ83_LEN - resid < 16) {
128*b8aa3defSJoshua M. Clulow 		smrt_command_free(smcm);
129*b8aa3defSJoshua M. Clulow 		return (EINVAL);
130*b8aa3defSJoshua M. Clulow 	}
131*b8aa3defSJoshua M. Clulow 	inq = smcm->smcm_internal->smcmi_va;
132*b8aa3defSJoshua M. Clulow 
133*b8aa3defSJoshua M. Clulow 	/*
134*b8aa3defSJoshua M. Clulow 	 * Sanity check we have the right page.
135*b8aa3defSJoshua M. Clulow 	 */
136*b8aa3defSJoshua M. Clulow 	if (inq[1] != 0x83) {
137*b8aa3defSJoshua M. Clulow 		smrt_command_free(smcm);
138*b8aa3defSJoshua M. Clulow 		return (EINVAL);
139*b8aa3defSJoshua M. Clulow 	}
140*b8aa3defSJoshua M. Clulow 
141*b8aa3defSJoshua M. Clulow 	/*
142*b8aa3defSJoshua M. Clulow 	 * Check to see if we have a proper Network Address Authority (NAA)
143*b8aa3defSJoshua M. Clulow 	 * based world wide number for this LUN.  It is possible that firmware
144*b8aa3defSJoshua M. Clulow 	 * interposes on this and constructs a fake world wide number (WWN).  If
145*b8aa3defSJoshua M. Clulow 	 * this is the case, we don't want to actually use it.  We need to
146*b8aa3defSJoshua M. Clulow 	 * verify that the WWN declares the correct naming authority and is of
147*b8aa3defSJoshua M. Clulow 	 * the proper length.
148*b8aa3defSJoshua M. Clulow 	 */
149*b8aa3defSJoshua M. Clulow 	if ((inq[5] & 0x30) != 0 || (inq[5] & 0x0f) != 3 || inq[7] != 8) {
150*b8aa3defSJoshua M. Clulow 		smrt_command_free(smcm);
151*b8aa3defSJoshua M. Clulow 		return (ENOTSUP);
152*b8aa3defSJoshua M. Clulow 	}
153*b8aa3defSJoshua M. Clulow 
154*b8aa3defSJoshua M. Clulow 	bcopy(&inq[8], &wwn, sizeof (uint64_t));
155*b8aa3defSJoshua M. Clulow 	*wwnp = BE_64(wwn);
156*b8aa3defSJoshua M. Clulow 
157*b8aa3defSJoshua M. Clulow 	smrt_command_free(smcm);
158*b8aa3defSJoshua M. Clulow 
159*b8aa3defSJoshua M. Clulow 	return (0);
160*b8aa3defSJoshua M. Clulow }
161