interface.c revision 59138
122347Spst/*-
222347Spst * Copyright (c) 1999 Michael Smith
329964Sache * All rights reserved.
492906Smarkm *
592906Smarkm * Redistribution and use in source and binary forms, with or without
622347Spst * modification, are permitted provided that the following conditions
722347Spst * are met:
822347Spst * 1. Redistributions of source code must retain the above copyright
922347Spst *    notice, this list of conditions and the following disclaimer.
1022347Spst * 2. Redistributions in binary form must reproduce the above copyright
1192906Smarkm *    notice, this list of conditions and the following disclaimer in the
1292906Smarkm *    documentation and/or other materials provided with the distribution.
1359118Skris *
1459118Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1559118Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1659118Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1729964Sache * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1829964Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1929964Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2022347Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2122347Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2222347Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2322347Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2422347Spst * SUCH DAMAGE.
2522347Spst *
2622347Spst *	$FreeBSD: cvs2svn/branches/MSMITH/usr.sbin/mlxcontrol/interface.c 59138 2000-04-11 03:01:45Z msmith $
2722347Spst */
2822347Spst
2922347Spst#include <fcntl.h>
3022347Spst#include <stdio.h>
3122347Spst#include <stdlib.h>
3229964Sache#include <unistd.h>
3322347Spst#include <string.h>
3422347Spst#include <cam/scsi/scsi_all.h>
3522347Spst
3622347Spst#if 0
3722347Spst#include <sys/mlxio.h>
3822347Spst#include <sys/mlxreg.h>
3922347Spst#else
4022347Spst#include "../sys/dev/mlx/mlxio.h"
4122347Spst#include "../sys/dev/mlx/mlxreg.h"
4222347Spst#endif
4322347Spst
4429964Sache#include "mlxcontrol.h"
4522347Spst
4622347Spst/********************************************************************************
4722347Spst * Iterate over all mlx devices, call (func) with each ones' path and (arg)
4822347Spst */
4922347Spstvoid
5022347Spstmlx_foreach(void (*func)(int unit, void *arg), void *arg)
5122347Spst{
5222347Spst    int		i, fd;
5322347Spst
5422347Spst    /* limit total count for sanity */
5522347Spst    for (i = 0; i < 64; i++) {
5622347Spst	/* verify we can open it */
5722347Spst	if ((fd = open(ctrlrpath(i), 0)) >= 0)
5822347Spst	    close(fd);
5922347Spst	/* if we can, do */
6022347Spst	if (fd >= 0) {
6122347Spst	    func(i, arg);
6222347Spst	}
6322347Spst    }
6422347Spst}
6522347Spst
6622347Spst/********************************************************************************
6722347Spst * Open the controller (unit) and give the fd to (func) along with (arg)
6822347Spst */
6922347Spstvoid
7022347Spstmlx_perform(int unit, void (*func)(int fd, void *arg), void *arg)
7122347Spst{
7292906Smarkm    int		fd;
7322347Spst
7422347Spst    if ((fd = open(ctrlrpath(unit), 0)) >= 0) {
7522347Spst	func(fd, arg);
7622347Spst	close(fd);
7722347Spst    }
7822347Spst}
7922347Spst
8022347Spst/********************************************************************************
8122347Spst * Iterate over all mlxd devices, call (func) with each ones' path and (arg)
8222347Spst */
8322347Spstvoid
8422347Spstmlxd_foreach_ctrlr(int unit, void *arg)
8592906Smarkm{
8622347Spst    struct mlxd_foreach_action	*ma = (struct mlxd_foreach_action *)arg;
8722347Spst    int				i, fd;
8892906Smarkm
8992906Smarkm    /* Get the device */
9092906Smarkm    if ((fd = open(ctrlrpath(unit), 0)) < 0)
9192906Smarkm	return;
9292906Smarkm
9392906Smarkm    for (i = -1; ;) {
9492906Smarkm	/* Get the unit number of the next child device */
9522347Spst	if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0)
9622347Spst	    return;
9722347Spst
9822347Spst	/* check that we can open this unit */
9922347Spst	if ((fd = open(drivepath(i), 0)) >= 0)
10022347Spst	    close(fd);
10122347Spst	/* if we can, do */
10222347Spst	if (fd >= 0) {
10322347Spst	    ma->func(i, ma->arg);
10422347Spst	}
10522347Spst    }
10622347Spst}
10722347Spst
10822347Spstvoid
10992906Smarkmmlxd_foreach(void (*func)(int unit, void *arg), void *arg)
11092906Smarkm{
11192906Smarkm    struct mlxd_foreach_action ma;
11292906Smarkm
11322347Spst    ma.func = func;
11492906Smarkm    ma.arg = arg;
11592906Smarkm    mlx_foreach(mlxd_foreach_ctrlr, &ma);
11692906Smarkm}
11792906Smarkm
11822347Spst/********************************************************************************
11922347Spst * Find the controller that manages the drive (unit), return controller number
12022347Spst * and system drive number on that controller.
12122347Spst */
12222347Spststatic struct
12392906Smarkm{
12492906Smarkm    int		unit;
12592906Smarkm    int		ctrlr;
12692906Smarkm    int		sysdrive;
12722347Spst} mlxd_find_ctrlr_param;
12822347Spst
12922347Spststatic void
13022347Spstmlxd_find_ctrlr_search(int unit, void *arg)
13122347Spst{
13292906Smarkm    int				i, fd;
13392906Smarkm
13492906Smarkm    /* Get the device */
13592906Smarkm    if ((fd = open(ctrlrpath(unit), 0)) >= 0) {
13622347Spst	for (i = -1; ;) {
13722347Spst	    /* Get the unit number of the next child device */
13829964Sache	    if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0)
13922347Spst		break;
14022347Spst
14122347Spst	    /* is this child the unit we want? */
14222347Spst	    if (i == mlxd_find_ctrlr_param.unit) {
14322347Spst		mlxd_find_ctrlr_param.ctrlr = unit;
14422347Spst		if (ioctl(fd, MLX_GET_SYSDRIVE, &i) == 0)
14522347Spst		    mlxd_find_ctrlr_param.sysdrive = i;
14622347Spst	    }
14722347Spst	}
14829964Sache	close(fd);
14992906Smarkm    }
15022347Spst}
15122347Spst
15292906Smarkmint
15322347Spstmlxd_find_ctrlr(int unit, int *ctrlr, int *sysdrive)
15422347Spst{
15522347Spst    mlxd_find_ctrlr_param.unit = unit;
15692906Smarkm    mlxd_find_ctrlr_param.ctrlr = -1;
15792906Smarkm    mlxd_find_ctrlr_param.sysdrive = -1;
15822347Spst
15992906Smarkm    mlx_foreach(mlxd_find_ctrlr_search, NULL);
16022347Spst    if ((mlxd_find_ctrlr_param.ctrlr != -1) && (mlxd_find_ctrlr_param.sysdrive != -1)) {
16122347Spst	*ctrlr = mlxd_find_ctrlr_param.ctrlr;
16222347Spst	*sysdrive = mlxd_find_ctrlr_param.sysdrive;
16322347Spst	return(0);
16422347Spst    }
16522347Spst    return(1);
16622347Spst}
16792906Smarkm
16822347Spst
16922347Spst/********************************************************************************
17022347Spst * Send a command to the controller on (fd)
17122347Spst */
17222347Spst
17322347Spstvoid
17422347Spstmlx_command(int fd, void *arg)
17522347Spst{
17622347Spst    struct mlx_usercommand	*cmd = (struct mlx_usercommand *)arg;
17722347Spst    int				error;
17822347Spst
17959118Skris    error = ioctl(fd, MLX_COMMAND, cmd);
18022347Spst    if (error != 0)
18159118Skris	cmd->mu_error = error;
18222347Spst}
18322347Spst
18422347Spst/********************************************************************************
18529964Sache * Perform an ENQUIRY2 command and return information related to the controller
18692906Smarkm * (unit)
18722347Spst */
18822347Spstint
18992906Smarkmmlx_enquiry(int unit, struct mlx_enquiry2 *enq)
19022347Spst{
19122347Spst    struct mlx_usercommand	cmd;
19222347Spst
19322347Spst    /* build the command */
19422347Spst    cmd.mu_datasize = sizeof(*enq);
19522347Spst    cmd.mu_buf = enq;
19622347Spst    cmd.mu_bufptr = 8;
19722347Spst    cmd.mu_command[0] = MLX_CMD_ENQUIRY2;
19822347Spst
19922347Spst    /* hand it off for processing */
20022347Spst    mlx_perform(unit, mlx_command, (void *)&cmd);
20122347Spst
20222347Spst    return(cmd.mu_status != 0);
20322347Spst}
20422347Spst
20522347Spst
20622347Spst/********************************************************************************
20722347Spst * Perform a READ CONFIGURATION command and return information related to the controller
20822347Spst * (unit)
20922347Spst */
21022347Spstint
21122347Spstmlx_read_configuration(int unit, struct mlx_core_cfg *cfg)
21222347Spst{
21392906Smarkm    struct mlx_usercommand	cmd;
21422347Spst
21522347Spst    /* build the command */
21622347Spst    cmd.mu_datasize = sizeof(*cfg);
21722347Spst    cmd.mu_buf = cfg;
21822347Spst    cmd.mu_bufptr = 8;
21922347Spst    cmd.mu_command[0] = MLX_CMD_READ_CONFIG;
22022347Spst
22122347Spst    /* hand it off for processing */
222    mlx_perform(unit, mlx_command, (void *)&cmd);
223
224    return(cmd.mu_status != 0);
225}
226
227/********************************************************************************
228 * Perform a SCSI INQUIRY command and return pointers to the relevant data.
229 */
230int
231mlx_scsi_inquiry(int unit, int channel, int target, char **vendor, char **device, char **revision)
232{
233    struct mlx_usercommand	cmd;
234    static struct {
235	    struct mlx_dcdb		dcdb;
236	    union {
237		struct scsi_inquiry_data	inq;
238		u_int8_t			pad[SHORT_INQUIRY_LENGTH];
239	    } d;
240    } __attribute__ ((packed))		dcdb_cmd;
241    struct scsi_inquiry		*inq_cmd = (struct scsi_inquiry *)&dcdb_cmd.dcdb.dcdb_cdb[0];
242
243    /* build the command */
244    cmd.mu_datasize = sizeof(dcdb_cmd);
245    cmd.mu_buf = &dcdb_cmd;
246    cmd.mu_command[0] = MLX_CMD_DIRECT_CDB;
247
248    /* build the DCDB */
249    bzero(&dcdb_cmd, sizeof(dcdb_cmd));
250    dcdb_cmd.dcdb.dcdb_channel = channel;
251    dcdb_cmd.dcdb.dcdb_target = target;
252    dcdb_cmd.dcdb.dcdb_flags = MLX_DCDB_DATA_IN | MLX_DCDB_TIMEOUT_10S;
253    dcdb_cmd.dcdb.dcdb_datasize = SHORT_INQUIRY_LENGTH;
254    dcdb_cmd.dcdb.dcdb_cdb_length = 6;
255    dcdb_cmd.dcdb.dcdb_sense_length = SSD_FULL_SIZE;
256
257    /* build the cdb */
258    inq_cmd->opcode = INQUIRY;
259    inq_cmd->length = SHORT_INQUIRY_LENGTH;
260
261    /* hand it off for processing */
262    mlx_perform(unit, mlx_command, &cmd);
263
264    if (cmd.mu_status == 0) {
265	*vendor = &dcdb_cmd.d.inq.vendor[0];
266	*device = &dcdb_cmd.d.inq.product[0];
267	*revision = &dcdb_cmd.d.inq.revision[0];
268    }
269    return(cmd.mu_status);
270}
271
272/********************************************************************************
273 * Perform a GET DEVICE STATE command and return pointers to the relevant data.
274 */
275int
276mlx_get_device_state(int unit, int channel, int target, struct mlx_phys_drv *drv)
277{
278    struct mlx_usercommand	cmd;
279
280    /* build the command */
281    cmd.mu_datasize = sizeof(*drv);
282    cmd.mu_buf = drv;
283    cmd.mu_bufptr = 8;
284    cmd.mu_command[0] = MLX_CMD_DEVICE_STATE;
285    cmd.mu_command[2] = channel;
286    cmd.mu_command[3] = target;
287
288    /* hand it off for processing */
289    mlx_perform(unit, mlx_command, (void *)&cmd);
290
291    return(cmd.mu_status != 0);
292}
293