interface.c revision 59159
159138Smsmith/*- 259138Smsmith * Copyright (c) 1999 Michael Smith 359138Smsmith * All rights reserved. 459138Smsmith * 559138Smsmith * Redistribution and use in source and binary forms, with or without 659138Smsmith * modification, are permitted provided that the following conditions 759138Smsmith * are met: 859138Smsmith * 1. Redistributions of source code must retain the above copyright 959138Smsmith * notice, this list of conditions and the following disclaimer. 1059138Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1159138Smsmith * notice, this list of conditions and the following disclaimer in the 1259138Smsmith * documentation and/or other materials provided with the distribution. 1359138Smsmith * 1459138Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1559138Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1659138Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1759138Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1859138Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1959138Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2059138Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2159138Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2259138Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2359138Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2459138Smsmith * SUCH DAMAGE. 2559138Smsmith * 2659138Smsmith * $FreeBSD: head/usr.sbin/mlxcontrol/interface.c 59159 2000-04-11 23:04:17Z msmith $ 2759138Smsmith */ 2859138Smsmith 2959138Smsmith#include <fcntl.h> 3059138Smsmith#include <stdio.h> 3159138Smsmith#include <stdlib.h> 3259138Smsmith#include <unistd.h> 3359138Smsmith#include <string.h> 3459138Smsmith#include <cam/scsi/scsi_all.h> 3559138Smsmith 3659159Smsmith#include <dev/mlx/mlxio.h> 3759159Smsmith#include <dev/mlx/mlxreg.h> 3859138Smsmith 3959138Smsmith#include "mlxcontrol.h" 4059138Smsmith 4159138Smsmith/******************************************************************************** 4259138Smsmith * Iterate over all mlx devices, call (func) with each ones' path and (arg) 4359138Smsmith */ 4459138Smsmithvoid 4559138Smsmithmlx_foreach(void (*func)(int unit, void *arg), void *arg) 4659138Smsmith{ 4759138Smsmith int i, fd; 4859138Smsmith 4959138Smsmith /* limit total count for sanity */ 5059138Smsmith for (i = 0; i < 64; i++) { 5159138Smsmith /* verify we can open it */ 5259138Smsmith if ((fd = open(ctrlrpath(i), 0)) >= 0) 5359138Smsmith close(fd); 5459138Smsmith /* if we can, do */ 5559138Smsmith if (fd >= 0) { 5659138Smsmith func(i, arg); 5759138Smsmith } 5859138Smsmith } 5959138Smsmith} 6059138Smsmith 6159138Smsmith/******************************************************************************** 6259138Smsmith * Open the controller (unit) and give the fd to (func) along with (arg) 6359138Smsmith */ 6459138Smsmithvoid 6559138Smsmithmlx_perform(int unit, void (*func)(int fd, void *arg), void *arg) 6659138Smsmith{ 6759138Smsmith int fd; 6859138Smsmith 6959138Smsmith if ((fd = open(ctrlrpath(unit), 0)) >= 0) { 7059138Smsmith func(fd, arg); 7159138Smsmith close(fd); 7259138Smsmith } 7359138Smsmith} 7459138Smsmith 7559138Smsmith/******************************************************************************** 7659138Smsmith * Iterate over all mlxd devices, call (func) with each ones' path and (arg) 7759138Smsmith */ 7859138Smsmithvoid 7959138Smsmithmlxd_foreach_ctrlr(int unit, void *arg) 8059138Smsmith{ 8159138Smsmith struct mlxd_foreach_action *ma = (struct mlxd_foreach_action *)arg; 8259138Smsmith int i, fd; 8359138Smsmith 8459138Smsmith /* Get the device */ 8559138Smsmith if ((fd = open(ctrlrpath(unit), 0)) < 0) 8659138Smsmith return; 8759138Smsmith 8859138Smsmith for (i = -1; ;) { 8959138Smsmith /* Get the unit number of the next child device */ 9059138Smsmith if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0) 9159138Smsmith return; 9259138Smsmith 9359138Smsmith /* check that we can open this unit */ 9459138Smsmith if ((fd = open(drivepath(i), 0)) >= 0) 9559138Smsmith close(fd); 9659138Smsmith /* if we can, do */ 9759138Smsmith if (fd >= 0) { 9859138Smsmith ma->func(i, ma->arg); 9959138Smsmith } 10059138Smsmith } 10159138Smsmith} 10259138Smsmith 10359138Smsmithvoid 10459138Smsmithmlxd_foreach(void (*func)(int unit, void *arg), void *arg) 10559138Smsmith{ 10659138Smsmith struct mlxd_foreach_action ma; 10759138Smsmith 10859138Smsmith ma.func = func; 10959138Smsmith ma.arg = arg; 11059138Smsmith mlx_foreach(mlxd_foreach_ctrlr, &ma); 11159138Smsmith} 11259138Smsmith 11359138Smsmith/******************************************************************************** 11459138Smsmith * Find the controller that manages the drive (unit), return controller number 11559138Smsmith * and system drive number on that controller. 11659138Smsmith */ 11759138Smsmithstatic struct 11859138Smsmith{ 11959138Smsmith int unit; 12059138Smsmith int ctrlr; 12159138Smsmith int sysdrive; 12259138Smsmith} mlxd_find_ctrlr_param; 12359138Smsmith 12459138Smsmithstatic void 12559138Smsmithmlxd_find_ctrlr_search(int unit, void *arg) 12659138Smsmith{ 12759138Smsmith int i, fd; 12859138Smsmith 12959138Smsmith /* Get the device */ 13059138Smsmith if ((fd = open(ctrlrpath(unit), 0)) >= 0) { 13159138Smsmith for (i = -1; ;) { 13259138Smsmith /* Get the unit number of the next child device */ 13359138Smsmith if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0) 13459138Smsmith break; 13559138Smsmith 13659138Smsmith /* is this child the unit we want? */ 13759138Smsmith if (i == mlxd_find_ctrlr_param.unit) { 13859138Smsmith mlxd_find_ctrlr_param.ctrlr = unit; 13959138Smsmith if (ioctl(fd, MLX_GET_SYSDRIVE, &i) == 0) 14059138Smsmith mlxd_find_ctrlr_param.sysdrive = i; 14159138Smsmith } 14259138Smsmith } 14359138Smsmith close(fd); 14459138Smsmith } 14559138Smsmith} 14659138Smsmith 14759138Smsmithint 14859138Smsmithmlxd_find_ctrlr(int unit, int *ctrlr, int *sysdrive) 14959138Smsmith{ 15059138Smsmith mlxd_find_ctrlr_param.unit = unit; 15159138Smsmith mlxd_find_ctrlr_param.ctrlr = -1; 15259138Smsmith mlxd_find_ctrlr_param.sysdrive = -1; 15359138Smsmith 15459138Smsmith mlx_foreach(mlxd_find_ctrlr_search, NULL); 15559138Smsmith if ((mlxd_find_ctrlr_param.ctrlr != -1) && (mlxd_find_ctrlr_param.sysdrive != -1)) { 15659138Smsmith *ctrlr = mlxd_find_ctrlr_param.ctrlr; 15759138Smsmith *sysdrive = mlxd_find_ctrlr_param.sysdrive; 15859138Smsmith return(0); 15959138Smsmith } 16059138Smsmith return(1); 16159138Smsmith} 16259138Smsmith 16359138Smsmith 16459138Smsmith/******************************************************************************** 16559138Smsmith * Send a command to the controller on (fd) 16659138Smsmith */ 16759138Smsmith 16859138Smsmithvoid 16959138Smsmithmlx_command(int fd, void *arg) 17059138Smsmith{ 17159138Smsmith struct mlx_usercommand *cmd = (struct mlx_usercommand *)arg; 17259138Smsmith int error; 17359138Smsmith 17459138Smsmith error = ioctl(fd, MLX_COMMAND, cmd); 17559138Smsmith if (error != 0) 17659138Smsmith cmd->mu_error = error; 17759138Smsmith} 17859138Smsmith 17959138Smsmith/******************************************************************************** 18059138Smsmith * Perform an ENQUIRY2 command and return information related to the controller 18159138Smsmith * (unit) 18259138Smsmith */ 18359138Smsmithint 18459138Smsmithmlx_enquiry(int unit, struct mlx_enquiry2 *enq) 18559138Smsmith{ 18659138Smsmith struct mlx_usercommand cmd; 18759138Smsmith 18859138Smsmith /* build the command */ 18959138Smsmith cmd.mu_datasize = sizeof(*enq); 19059138Smsmith cmd.mu_buf = enq; 19159138Smsmith cmd.mu_bufptr = 8; 19259138Smsmith cmd.mu_command[0] = MLX_CMD_ENQUIRY2; 19359138Smsmith 19459138Smsmith /* hand it off for processing */ 19559138Smsmith mlx_perform(unit, mlx_command, (void *)&cmd); 19659138Smsmith 19759138Smsmith return(cmd.mu_status != 0); 19859138Smsmith} 19959138Smsmith 20059138Smsmith 20159138Smsmith/******************************************************************************** 20259138Smsmith * Perform a READ CONFIGURATION command and return information related to the controller 20359138Smsmith * (unit) 20459138Smsmith */ 20559138Smsmithint 20659138Smsmithmlx_read_configuration(int unit, struct mlx_core_cfg *cfg) 20759138Smsmith{ 20859138Smsmith struct mlx_usercommand cmd; 20959138Smsmith 21059138Smsmith /* build the command */ 21159138Smsmith cmd.mu_datasize = sizeof(*cfg); 21259138Smsmith cmd.mu_buf = cfg; 21359138Smsmith cmd.mu_bufptr = 8; 21459138Smsmith cmd.mu_command[0] = MLX_CMD_READ_CONFIG; 21559138Smsmith 21659138Smsmith /* hand it off for processing */ 21759138Smsmith mlx_perform(unit, mlx_command, (void *)&cmd); 21859138Smsmith 21959138Smsmith return(cmd.mu_status != 0); 22059138Smsmith} 22159138Smsmith 22259138Smsmith/******************************************************************************** 22359138Smsmith * Perform a SCSI INQUIRY command and return pointers to the relevant data. 22459138Smsmith */ 22559138Smsmithint 22659138Smsmithmlx_scsi_inquiry(int unit, int channel, int target, char **vendor, char **device, char **revision) 22759138Smsmith{ 22859138Smsmith struct mlx_usercommand cmd; 22959138Smsmith static struct { 23059138Smsmith struct mlx_dcdb dcdb; 23159138Smsmith union { 23259138Smsmith struct scsi_inquiry_data inq; 23359138Smsmith u_int8_t pad[SHORT_INQUIRY_LENGTH]; 23459138Smsmith } d; 23559138Smsmith } __attribute__ ((packed)) dcdb_cmd; 23659138Smsmith struct scsi_inquiry *inq_cmd = (struct scsi_inquiry *)&dcdb_cmd.dcdb.dcdb_cdb[0]; 23759138Smsmith 23859138Smsmith /* build the command */ 23959138Smsmith cmd.mu_datasize = sizeof(dcdb_cmd); 24059138Smsmith cmd.mu_buf = &dcdb_cmd; 24159138Smsmith cmd.mu_command[0] = MLX_CMD_DIRECT_CDB; 24259138Smsmith 24359138Smsmith /* build the DCDB */ 24459138Smsmith bzero(&dcdb_cmd, sizeof(dcdb_cmd)); 24559138Smsmith dcdb_cmd.dcdb.dcdb_channel = channel; 24659138Smsmith dcdb_cmd.dcdb.dcdb_target = target; 24759138Smsmith dcdb_cmd.dcdb.dcdb_flags = MLX_DCDB_DATA_IN | MLX_DCDB_TIMEOUT_10S; 24859138Smsmith dcdb_cmd.dcdb.dcdb_datasize = SHORT_INQUIRY_LENGTH; 24959138Smsmith dcdb_cmd.dcdb.dcdb_cdb_length = 6; 25059138Smsmith dcdb_cmd.dcdb.dcdb_sense_length = SSD_FULL_SIZE; 25159138Smsmith 25259138Smsmith /* build the cdb */ 25359138Smsmith inq_cmd->opcode = INQUIRY; 25459138Smsmith inq_cmd->length = SHORT_INQUIRY_LENGTH; 25559138Smsmith 25659138Smsmith /* hand it off for processing */ 25759138Smsmith mlx_perform(unit, mlx_command, &cmd); 25859138Smsmith 25959138Smsmith if (cmd.mu_status == 0) { 26059138Smsmith *vendor = &dcdb_cmd.d.inq.vendor[0]; 26159138Smsmith *device = &dcdb_cmd.d.inq.product[0]; 26259138Smsmith *revision = &dcdb_cmd.d.inq.revision[0]; 26359138Smsmith } 26459138Smsmith return(cmd.mu_status); 26559138Smsmith} 26659138Smsmith 26759138Smsmith/******************************************************************************** 26859138Smsmith * Perform a GET DEVICE STATE command and return pointers to the relevant data. 26959138Smsmith */ 27059138Smsmithint 27159138Smsmithmlx_get_device_state(int unit, int channel, int target, struct mlx_phys_drv *drv) 27259138Smsmith{ 27359138Smsmith struct mlx_usercommand cmd; 27459138Smsmith 27559138Smsmith /* build the command */ 27659138Smsmith cmd.mu_datasize = sizeof(*drv); 27759138Smsmith cmd.mu_buf = drv; 27859138Smsmith cmd.mu_bufptr = 8; 27959138Smsmith cmd.mu_command[0] = MLX_CMD_DEVICE_STATE; 28059138Smsmith cmd.mu_command[2] = channel; 28159138Smsmith cmd.mu_command[3] = target; 28259138Smsmith 28359138Smsmith /* hand it off for processing */ 28459138Smsmith mlx_perform(unit, mlx_command, (void *)&cmd); 28559138Smsmith 28659138Smsmith return(cmd.mu_status != 0); 28759138Smsmith} 288