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