1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1999 Michael Smith 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <fcntl.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <string.h> 36 #include <cam/scsi/scsi_all.h> 37 38 #include <dev/mlx/mlxio.h> 39 #include <dev/mlx/mlxreg.h> 40 41 #include "mlxcontrol.h" 42 43 /******************************************************************************** 44 * Iterate over all mlx devices, call (func) with each ones' path and (arg) 45 */ 46 void 47 mlx_foreach(void (*func)(int unit, void *arg), void *arg) 48 { 49 int i, fd; 50 51 /* limit total count for sanity */ 52 for (i = 0; i < 64; i++) { 53 /* verify we can open it */ 54 if ((fd = open(ctrlrpath(i), 0)) >= 0) 55 close(fd); 56 /* if we can, do */ 57 if (fd >= 0) { 58 func(i, arg); 59 } 60 } 61 } 62 63 /******************************************************************************** 64 * Open the controller (unit) and give the fd to (func) along with (arg) 65 */ 66 void 67 mlx_perform(int unit, void (*func)(int fd, void *arg), void *arg) 68 { 69 int fd; 70 71 if ((fd = open(ctrlrpath(unit), 0)) >= 0) { 72 func(fd, arg); 73 close(fd); 74 } 75 } 76 77 /******************************************************************************** 78 * Iterate over all mlxd devices, call (func) with each ones' path and (arg) 79 */ 80 void 81 mlxd_foreach_ctrlr(int unit, void *arg) 82 { 83 struct mlxd_foreach_action *ma = (struct mlxd_foreach_action *)arg; 84 int i, fd, ctrlfd; 85 86 /* Get the device */ 87 if ((ctrlfd = open(ctrlrpath(unit), 0)) < 0) 88 return; 89 90 for (i = -1; ;) { 91 /* Get the unit number of the next child device */ 92 if (ioctl(ctrlfd, MLX_NEXT_CHILD, &i) < 0) { 93 close(ctrlfd); 94 return; 95 } 96 97 /* check that we can open this unit */ 98 if ((fd = open(drivepath(i), 0)) >= 0) 99 close(fd); 100 /* if we can, do */ 101 if (fd >= 0) { 102 ma->func(i, ma->arg); 103 } 104 } 105 } 106 107 void 108 mlxd_foreach(void (*func)(int unit, void *arg), void *arg) 109 { 110 struct mlxd_foreach_action ma; 111 112 ma.func = func; 113 ma.arg = arg; 114 mlx_foreach(mlxd_foreach_ctrlr, &ma); 115 } 116 117 /******************************************************************************** 118 * Find the controller that manages the drive (unit), return controller number 119 * and system drive number on that controller. 120 */ 121 static struct 122 { 123 int unit; 124 int ctrlr; 125 int sysdrive; 126 } mlxd_find_ctrlr_param; 127 128 static void 129 mlxd_find_ctrlr_search(int unit, void *arg) 130 { 131 int i, fd; 132 133 /* Get the device */ 134 if ((fd = open(ctrlrpath(unit), 0)) >= 0) { 135 for (i = -1; ;) { 136 /* Get the unit number of the next child device */ 137 if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0) 138 break; 139 140 /* is this child the unit we want? */ 141 if (i == mlxd_find_ctrlr_param.unit) { 142 mlxd_find_ctrlr_param.ctrlr = unit; 143 if (ioctl(fd, MLX_GET_SYSDRIVE, &i) == 0) 144 mlxd_find_ctrlr_param.sysdrive = i; 145 } 146 } 147 close(fd); 148 } 149 } 150 151 int 152 mlxd_find_ctrlr(int unit, int *ctrlr, int *sysdrive) 153 { 154 mlxd_find_ctrlr_param.unit = unit; 155 mlxd_find_ctrlr_param.ctrlr = -1; 156 mlxd_find_ctrlr_param.sysdrive = -1; 157 158 mlx_foreach(mlxd_find_ctrlr_search, NULL); 159 if ((mlxd_find_ctrlr_param.ctrlr != -1) && (mlxd_find_ctrlr_param.sysdrive != -1)) { 160 *ctrlr = mlxd_find_ctrlr_param.ctrlr; 161 *sysdrive = mlxd_find_ctrlr_param.sysdrive; 162 return(0); 163 } 164 return(1); 165 } 166 167 168 /******************************************************************************** 169 * Send a command to the controller on (fd) 170 */ 171 172 void 173 mlx_command(int fd, void *arg) 174 { 175 struct mlx_usercommand *cmd = (struct mlx_usercommand *)arg; 176 int error; 177 178 error = ioctl(fd, MLX_COMMAND, cmd); 179 if (error != 0) 180 cmd->mu_error = error; 181 } 182 183 /******************************************************************************** 184 * Perform an ENQUIRY2 command and return information related to the controller 185 * (unit) 186 */ 187 int 188 mlx_enquiry(int unit, struct mlx_enquiry2 *enq) 189 { 190 struct mlx_usercommand cmd; 191 192 /* build the command */ 193 cmd.mu_datasize = sizeof(*enq); 194 cmd.mu_buf = enq; 195 cmd.mu_bufptr = 8; 196 cmd.mu_command[0] = MLX_CMD_ENQUIRY2; 197 198 /* hand it off for processing */ 199 mlx_perform(unit, mlx_command, (void *)&cmd); 200 201 return(cmd.mu_status != 0); 202 } 203 204 205 /******************************************************************************** 206 * Perform a READ CONFIGURATION command and return information related to the controller 207 * (unit) 208 */ 209 int 210 mlx_read_configuration(int unit, struct mlx_core_cfg *cfg) 211 { 212 struct mlx_usercommand cmd; 213 214 /* build the command */ 215 cmd.mu_datasize = sizeof(*cfg); 216 cmd.mu_buf = cfg; 217 cmd.mu_bufptr = 8; 218 cmd.mu_command[0] = MLX_CMD_READ_CONFIG; 219 220 /* hand it off for processing */ 221 mlx_perform(unit, mlx_command, (void *)&cmd); 222 223 return(cmd.mu_status != 0); 224 } 225 226 /******************************************************************************** 227 * Perform a SCSI INQUIRY command and return pointers to the relevant data. 228 */ 229 int 230 mlx_scsi_inquiry(int unit, int channel, int target, char **vendor, char **device, char **revision) 231 { 232 struct mlx_usercommand cmd; 233 static struct { 234 struct mlx_dcdb dcdb; 235 union { 236 struct scsi_inquiry_data inq; 237 u_int8_t pad[SHORT_INQUIRY_LENGTH]; 238 } d; 239 } __attribute__ ((packed)) dcdb_cmd; 240 struct scsi_inquiry *inq_cmd = (struct scsi_inquiry *)&dcdb_cmd.dcdb.dcdb_cdb[0]; 241 242 /* build the command */ 243 cmd.mu_datasize = sizeof(dcdb_cmd); 244 cmd.mu_buf = &dcdb_cmd; 245 cmd.mu_command[0] = MLX_CMD_DIRECT_CDB; 246 247 /* build the DCDB */ 248 bzero(&dcdb_cmd, sizeof(dcdb_cmd)); 249 dcdb_cmd.dcdb.dcdb_channel = channel; 250 dcdb_cmd.dcdb.dcdb_target = target; 251 dcdb_cmd.dcdb.dcdb_flags = MLX_DCDB_DATA_IN | MLX_DCDB_TIMEOUT_10S; 252 dcdb_cmd.dcdb.dcdb_datasize = SHORT_INQUIRY_LENGTH; 253 dcdb_cmd.dcdb.dcdb_cdb_length = 6; 254 dcdb_cmd.dcdb.dcdb_sense_length = SSD_FULL_SIZE; 255 256 /* build the cdb */ 257 inq_cmd->opcode = INQUIRY; 258 scsi_ulto2b(SHORT_INQUIRY_LENGTH, inq_cmd->length); 259 260 /* hand it off for processing */ 261 mlx_perform(unit, mlx_command, &cmd); 262 263 if (cmd.mu_status == 0) { 264 *vendor = &dcdb_cmd.d.inq.vendor[0]; 265 *device = &dcdb_cmd.d.inq.product[0]; 266 *revision = &dcdb_cmd.d.inq.revision[0]; 267 } 268 return(cmd.mu_status); 269 } 270 271 /******************************************************************************** 272 * Perform a GET DEVICE STATE command and return pointers to the relevant data. 273 */ 274 int 275 mlx_get_device_state(int unit, int channel, int target, struct mlx_phys_drv *drv) 276 { 277 struct mlx_usercommand cmd; 278 279 /* build the command */ 280 cmd.mu_datasize = sizeof(*drv); 281 cmd.mu_buf = drv; 282 cmd.mu_bufptr = 8; 283 cmd.mu_command[0] = MLX_CMD_DEVICE_STATE; 284 cmd.mu_command[2] = channel; 285 cmd.mu_command[3] = target; 286 287 /* hand it off for processing */ 288 mlx_perform(unit, mlx_command, (void *)&cmd); 289 290 return(cmd.mu_status != 0); 291 } 292