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