diff options
Diffstat (limited to 'usr.sbin/mlxcontrol/interface.c')
-rw-r--r-- | usr.sbin/mlxcontrol/interface.c | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/usr.sbin/mlxcontrol/interface.c b/usr.sbin/mlxcontrol/interface.c new file mode 100644 index 0000000..a2c5dfa --- /dev/null +++ b/usr.sbin/mlxcontrol/interface.c @@ -0,0 +1,292 @@ +/*- + * Copyright (c) 1999 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <cam/scsi/scsi_all.h> + +#if 0 +#include <sys/mlxio.h> +#include <sys/mlxreg.h> +#else +#include "../sys/dev/mlx/mlxio.h" +#include "../sys/dev/mlx/mlxreg.h" +#endif + +#include "mlxcontrol.h" + +/******************************************************************************** + * Iterate over all mlx devices, call (func) with each ones' path and (arg) + */ +void +mlx_foreach(void (*func)(int unit, void *arg), void *arg) +{ + int i, fd; + + /* limit total count for sanity */ + for (i = 0; i < 64; i++) { + /* verify we can open it */ + if ((fd = open(ctrlrpath(i), 0)) >= 0) + close(fd); + /* if we can, do */ + if (fd >= 0) { + func(i, arg); + } + } +} + +/******************************************************************************** + * Open the controller (unit) and give the fd to (func) along with (arg) + */ +void +mlx_perform(int unit, void (*func)(int fd, void *arg), void *arg) +{ + int fd; + + if ((fd = open(ctrlrpath(unit), 0)) >= 0) { + func(fd, arg); + close(fd); + } +} + +/******************************************************************************** + * Iterate over all mlxd devices, call (func) with each ones' path and (arg) + */ +void +mlxd_foreach_ctrlr(int unit, void *arg) +{ + struct mlxd_foreach_action *ma = (struct mlxd_foreach_action *)arg; + int i, fd; + + /* Get the device */ + if ((fd = open(ctrlrpath(unit), 0)) < 0) + return; + + for (i = -1; ;) { + /* Get the unit number of the next child device */ + if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0) + return; + + /* check that we can open this unit */ + if ((fd = open(drivepath(i), 0)) >= 0) + close(fd); + /* if we can, do */ + if (fd >= 0) { + ma->func(i, ma->arg); + } + } +} + +void +mlxd_foreach(void (*func)(int unit, void *arg), void *arg) +{ + struct mlxd_foreach_action ma; + + ma.func = func; + ma.arg = arg; + mlx_foreach(mlxd_foreach_ctrlr, &ma); +} + +/******************************************************************************** + * Find the controller that manages the drive (unit), return controller number + * and system drive number on that controller. + */ +static struct +{ + int unit; + int ctrlr; + int sysdrive; +} mlxd_find_ctrlr_param; + +static void +mlxd_find_ctrlr_search(int unit, void *arg) +{ + int i, fd; + + /* Get the device */ + if ((fd = open(ctrlrpath(unit), 0)) >= 0) { + for (i = -1; ;) { + /* Get the unit number of the next child device */ + if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0) + break; + + /* is this child the unit we want? */ + if (i == mlxd_find_ctrlr_param.unit) { + mlxd_find_ctrlr_param.ctrlr = unit; + if (ioctl(fd, MLX_GET_SYSDRIVE, &i) == 0) + mlxd_find_ctrlr_param.sysdrive = i; + } + } + close(fd); + } +} + +int +mlxd_find_ctrlr(int unit, int *ctrlr, int *sysdrive) +{ + mlxd_find_ctrlr_param.unit = unit; + mlxd_find_ctrlr_param.ctrlr = -1; + mlxd_find_ctrlr_param.sysdrive = -1; + + mlx_foreach(mlxd_find_ctrlr_search, NULL); + if ((mlxd_find_ctrlr_param.ctrlr != -1) && (mlxd_find_ctrlr_param.sysdrive != -1)) { + *ctrlr = mlxd_find_ctrlr_param.ctrlr; + *sysdrive = mlxd_find_ctrlr_param.sysdrive; + return(0); + } + return(1); +} + + +/******************************************************************************** + * Send a command to the controller on (fd) + */ + +void +mlx_command(int fd, void *arg) +{ + struct mlx_usercommand *cmd = (struct mlx_usercommand *)arg; + int error; + + error = ioctl(fd, MLX_COMMAND, cmd); + if (error != 0) + cmd->mu_error = error; +} + +/******************************************************************************** + * Perform an ENQUIRY2 command and return information related to the controller + * (unit) + */ +int +mlx_enquiry(int unit, struct mlx_enquiry2 *enq) +{ + struct mlx_usercommand cmd; + + /* build the command */ + cmd.mu_datasize = sizeof(*enq); + cmd.mu_buf = enq; + cmd.mu_bufptr = 8; + cmd.mu_command[0] = MLX_CMD_ENQUIRY2; + + /* hand it off for processing */ + mlx_perform(unit, mlx_command, (void *)&cmd); + + return(cmd.mu_status != 0); +} + + +/******************************************************************************** + * Perform a READ CONFIGURATION command and return information related to the controller + * (unit) + */ +int +mlx_read_configuration(int unit, struct mlx_core_cfg *cfg) +{ + struct mlx_usercommand cmd; + + /* build the command */ + cmd.mu_datasize = sizeof(*cfg); + cmd.mu_buf = cfg; + cmd.mu_bufptr = 8; + cmd.mu_command[0] = MLX_CMD_READ_CONFIG; + + /* hand it off for processing */ + mlx_perform(unit, mlx_command, (void *)&cmd); + + return(cmd.mu_status != 0); +} + +/******************************************************************************** + * Perform a SCSI INQUIRY command and return pointers to the relevant data. + */ +int +mlx_scsi_inquiry(int unit, int channel, int target, char **vendor, char **device, char **revision) +{ + struct mlx_usercommand cmd; + static struct { + struct mlx_dcdb dcdb; + union { + struct scsi_inquiry_data inq; + u_int8_t pad[SHORT_INQUIRY_LENGTH]; + } d; + } __attribute__ ((packed)) dcdb_cmd; + struct scsi_inquiry *inq_cmd = (struct scsi_inquiry *)&dcdb_cmd.dcdb.dcdb_cdb[0]; + + /* build the command */ + cmd.mu_datasize = sizeof(dcdb_cmd); + cmd.mu_buf = &dcdb_cmd; + cmd.mu_command[0] = MLX_CMD_DIRECT_CDB; + + /* build the DCDB */ + bzero(&dcdb_cmd, sizeof(dcdb_cmd)); + dcdb_cmd.dcdb.dcdb_channel = channel; + dcdb_cmd.dcdb.dcdb_target = target; + dcdb_cmd.dcdb.dcdb_flags = MLX_DCDB_DATA_IN | MLX_DCDB_TIMEOUT_10S; + dcdb_cmd.dcdb.dcdb_datasize = SHORT_INQUIRY_LENGTH; + dcdb_cmd.dcdb.dcdb_cdb_length = 6; + dcdb_cmd.dcdb.dcdb_sense_length = SSD_FULL_SIZE; + + /* build the cdb */ + inq_cmd->opcode = INQUIRY; + inq_cmd->length = SHORT_INQUIRY_LENGTH; + + /* hand it off for processing */ + mlx_perform(unit, mlx_command, &cmd); + + if (cmd.mu_status == 0) { + *vendor = &dcdb_cmd.d.inq.vendor[0]; + *device = &dcdb_cmd.d.inq.product[0]; + *revision = &dcdb_cmd.d.inq.revision[0]; + } + return(cmd.mu_status); +} + +/******************************************************************************** + * Perform a GET DEVICE STATE command and return pointers to the relevant data. + */ +int +mlx_get_device_state(int unit, int channel, int target, struct mlx_phys_drv *drv) +{ + struct mlx_usercommand cmd; + + /* build the command */ + cmd.mu_datasize = sizeof(*drv); + cmd.mu_buf = drv; + cmd.mu_bufptr = 8; + cmd.mu_command[0] = MLX_CMD_DEVICE_STATE; + cmd.mu_command[2] = channel; + cmd.mu_command[3] = target; + + /* hand it off for processing */ + mlx_perform(unit, mlx_command, (void *)&cmd); + + return(cmd.mu_status != 0); +} |