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$ 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; 82182965Ssepotvin int i, fd, ctrlfd; 8359138Smsmith 8459138Smsmith /* Get the device */ 85182965Ssepotvin if ((ctrlfd = open(ctrlrpath(unit), 0)) < 0) 8659138Smsmith return; 8759138Smsmith 8859138Smsmith for (i = -1; ;) { 8959138Smsmith /* Get the unit number of the next child device */ 90182965Ssepotvin if (ioctl(ctrlfd, MLX_NEXT_CHILD, &i) < 0) { 91182965Ssepotvin close(ctrlfd); 9259138Smsmith return; 93182965Ssepotvin } 9459138Smsmith 9559138Smsmith /* check that we can open this unit */ 9659138Smsmith if ((fd = open(drivepath(i), 0)) >= 0) 9759138Smsmith close(fd); 9859138Smsmith /* if we can, do */ 9959138Smsmith if (fd >= 0) { 10059138Smsmith ma->func(i, ma->arg); 10159138Smsmith } 10259138Smsmith } 10359138Smsmith} 10459138Smsmith 10559138Smsmithvoid 10659138Smsmithmlxd_foreach(void (*func)(int unit, void *arg), void *arg) 10759138Smsmith{ 10859138Smsmith struct mlxd_foreach_action ma; 10959138Smsmith 11059138Smsmith ma.func = func; 11159138Smsmith ma.arg = arg; 11259138Smsmith mlx_foreach(mlxd_foreach_ctrlr, &ma); 11359138Smsmith} 11459138Smsmith 11559138Smsmith/******************************************************************************** 11659138Smsmith * Find the controller that manages the drive (unit), return controller number 11759138Smsmith * and system drive number on that controller. 11859138Smsmith */ 11959138Smsmithstatic struct 12059138Smsmith{ 12159138Smsmith int unit; 12259138Smsmith int ctrlr; 12359138Smsmith int sysdrive; 12459138Smsmith} mlxd_find_ctrlr_param; 12559138Smsmith 12659138Smsmithstatic void 12759138Smsmithmlxd_find_ctrlr_search(int unit, void *arg) 12859138Smsmith{ 12959138Smsmith int i, fd; 13059138Smsmith 13159138Smsmith /* Get the device */ 13259138Smsmith if ((fd = open(ctrlrpath(unit), 0)) >= 0) { 13359138Smsmith for (i = -1; ;) { 13459138Smsmith /* Get the unit number of the next child device */ 13559138Smsmith if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0) 13659138Smsmith break; 13759138Smsmith 13859138Smsmith /* is this child the unit we want? */ 13959138Smsmith if (i == mlxd_find_ctrlr_param.unit) { 14059138Smsmith mlxd_find_ctrlr_param.ctrlr = unit; 14159138Smsmith if (ioctl(fd, MLX_GET_SYSDRIVE, &i) == 0) 14259138Smsmith mlxd_find_ctrlr_param.sysdrive = i; 14359138Smsmith } 14459138Smsmith } 14559138Smsmith close(fd); 14659138Smsmith } 14759138Smsmith} 14859138Smsmith 14959138Smsmithint 15059138Smsmithmlxd_find_ctrlr(int unit, int *ctrlr, int *sysdrive) 15159138Smsmith{ 15259138Smsmith mlxd_find_ctrlr_param.unit = unit; 15359138Smsmith mlxd_find_ctrlr_param.ctrlr = -1; 15459138Smsmith mlxd_find_ctrlr_param.sysdrive = -1; 15559138Smsmith 15659138Smsmith mlx_foreach(mlxd_find_ctrlr_search, NULL); 15759138Smsmith if ((mlxd_find_ctrlr_param.ctrlr != -1) && (mlxd_find_ctrlr_param.sysdrive != -1)) { 15859138Smsmith *ctrlr = mlxd_find_ctrlr_param.ctrlr; 15959138Smsmith *sysdrive = mlxd_find_ctrlr_param.sysdrive; 16059138Smsmith return(0); 16159138Smsmith } 16259138Smsmith return(1); 16359138Smsmith} 16459138Smsmith 16559138Smsmith 16659138Smsmith/******************************************************************************** 16759138Smsmith * Send a command to the controller on (fd) 16859138Smsmith */ 16959138Smsmith 17059138Smsmithvoid 17159138Smsmithmlx_command(int fd, void *arg) 17259138Smsmith{ 17359138Smsmith struct mlx_usercommand *cmd = (struct mlx_usercommand *)arg; 17459138Smsmith int error; 17559138Smsmith 17659138Smsmith error = ioctl(fd, MLX_COMMAND, cmd); 17759138Smsmith if (error != 0) 17859138Smsmith cmd->mu_error = error; 17959138Smsmith} 18059138Smsmith 18159138Smsmith/******************************************************************************** 18259138Smsmith * Perform an ENQUIRY2 command and return information related to the controller 18359138Smsmith * (unit) 18459138Smsmith */ 18559138Smsmithint 18659138Smsmithmlx_enquiry(int unit, struct mlx_enquiry2 *enq) 18759138Smsmith{ 18859138Smsmith struct mlx_usercommand cmd; 18959138Smsmith 19059138Smsmith /* build the command */ 19159138Smsmith cmd.mu_datasize = sizeof(*enq); 19259138Smsmith cmd.mu_buf = enq; 19359138Smsmith cmd.mu_bufptr = 8; 19459138Smsmith cmd.mu_command[0] = MLX_CMD_ENQUIRY2; 19559138Smsmith 19659138Smsmith /* hand it off for processing */ 19759138Smsmith mlx_perform(unit, mlx_command, (void *)&cmd); 19859138Smsmith 19959138Smsmith return(cmd.mu_status != 0); 20059138Smsmith} 20159138Smsmith 20259138Smsmith 20359138Smsmith/******************************************************************************** 20459138Smsmith * Perform a READ CONFIGURATION command and return information related to the controller 20559138Smsmith * (unit) 20659138Smsmith */ 20759138Smsmithint 20859138Smsmithmlx_read_configuration(int unit, struct mlx_core_cfg *cfg) 20959138Smsmith{ 21059138Smsmith struct mlx_usercommand cmd; 21159138Smsmith 21259138Smsmith /* build the command */ 21359138Smsmith cmd.mu_datasize = sizeof(*cfg); 21459138Smsmith cmd.mu_buf = cfg; 21559138Smsmith cmd.mu_bufptr = 8; 21659138Smsmith cmd.mu_command[0] = MLX_CMD_READ_CONFIG; 21759138Smsmith 21859138Smsmith /* hand it off for processing */ 21959138Smsmith mlx_perform(unit, mlx_command, (void *)&cmd); 22059138Smsmith 22159138Smsmith return(cmd.mu_status != 0); 22259138Smsmith} 22359138Smsmith 22459138Smsmith/******************************************************************************** 22559138Smsmith * Perform a SCSI INQUIRY command and return pointers to the relevant data. 22659138Smsmith */ 22759138Smsmithint 22859138Smsmithmlx_scsi_inquiry(int unit, int channel, int target, char **vendor, char **device, char **revision) 22959138Smsmith{ 23059138Smsmith struct mlx_usercommand cmd; 23159138Smsmith static struct { 23259138Smsmith struct mlx_dcdb dcdb; 23359138Smsmith union { 23459138Smsmith struct scsi_inquiry_data inq; 23559138Smsmith u_int8_t pad[SHORT_INQUIRY_LENGTH]; 23659138Smsmith } d; 23759138Smsmith } __attribute__ ((packed)) dcdb_cmd; 23859138Smsmith struct scsi_inquiry *inq_cmd = (struct scsi_inquiry *)&dcdb_cmd.dcdb.dcdb_cdb[0]; 23959138Smsmith 24059138Smsmith /* build the command */ 24159138Smsmith cmd.mu_datasize = sizeof(dcdb_cmd); 24259138Smsmith cmd.mu_buf = &dcdb_cmd; 24359138Smsmith cmd.mu_command[0] = MLX_CMD_DIRECT_CDB; 24459138Smsmith 24559138Smsmith /* build the DCDB */ 24659138Smsmith bzero(&dcdb_cmd, sizeof(dcdb_cmd)); 24759138Smsmith dcdb_cmd.dcdb.dcdb_channel = channel; 24859138Smsmith dcdb_cmd.dcdb.dcdb_target = target; 24959138Smsmith dcdb_cmd.dcdb.dcdb_flags = MLX_DCDB_DATA_IN | MLX_DCDB_TIMEOUT_10S; 25059138Smsmith dcdb_cmd.dcdb.dcdb_datasize = SHORT_INQUIRY_LENGTH; 25159138Smsmith dcdb_cmd.dcdb.dcdb_cdb_length = 6; 25259138Smsmith dcdb_cmd.dcdb.dcdb_sense_length = SSD_FULL_SIZE; 25359138Smsmith 25459138Smsmith /* build the cdb */ 25559138Smsmith inq_cmd->opcode = INQUIRY; 256229997Sken scsi_ulto2b(SHORT_INQUIRY_LENGTH, inq_cmd->length); 25759138Smsmith 25859138Smsmith /* hand it off for processing */ 25959138Smsmith mlx_perform(unit, mlx_command, &cmd); 26059138Smsmith 26159138Smsmith if (cmd.mu_status == 0) { 26259138Smsmith *vendor = &dcdb_cmd.d.inq.vendor[0]; 26359138Smsmith *device = &dcdb_cmd.d.inq.product[0]; 26459138Smsmith *revision = &dcdb_cmd.d.inq.revision[0]; 26559138Smsmith } 26659138Smsmith return(cmd.mu_status); 26759138Smsmith} 26859138Smsmith 26959138Smsmith/******************************************************************************** 27059138Smsmith * Perform a GET DEVICE STATE command and return pointers to the relevant data. 27159138Smsmith */ 27259138Smsmithint 27359138Smsmithmlx_get_device_state(int unit, int channel, int target, struct mlx_phys_drv *drv) 27459138Smsmith{ 27559138Smsmith struct mlx_usercommand cmd; 27659138Smsmith 27759138Smsmith /* build the command */ 27859138Smsmith cmd.mu_datasize = sizeof(*drv); 27959138Smsmith cmd.mu_buf = drv; 28059138Smsmith cmd.mu_bufptr = 8; 28159138Smsmith cmd.mu_command[0] = MLX_CMD_DEVICE_STATE; 28259138Smsmith cmd.mu_command[2] = channel; 28359138Smsmith cmd.mu_command[3] = target; 28459138Smsmith 28559138Smsmith /* hand it off for processing */ 28659138Smsmith mlx_perform(unit, mlx_command, (void *)&cmd); 28759138Smsmith 28859138Smsmith return(cmd.mu_status != 0); 28959138Smsmith} 290