interface.c revision 59138
1251655Sadrian/*-
2251655Sadrian * Copyright (c) 1999 Michael Smith
3251655Sadrian * All rights reserved.
4251655Sadrian *
5251655Sadrian * Redistribution and use in source and binary forms, with or without
6251655Sadrian * modification, are permitted provided that the following conditions
7251655Sadrian * are met:
8251655Sadrian * 1. Redistributions of source code must retain the above copyright
9251655Sadrian *    notice, this list of conditions and the following disclaimer.
10251655Sadrian * 2. Redistributions in binary form must reproduce the above copyright
11251655Sadrian *    notice, this list of conditions and the following disclaimer in the
12251655Sadrian *    documentation and/or other materials provided with the distribution.
13251655Sadrian *
14251655Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15251655Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16251655Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17251655Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18251655Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19251655Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20251655Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21251655Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22251655Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23251655Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24251655Sadrian * SUCH DAMAGE.
25251655Sadrian *
26251655Sadrian *	$FreeBSD: cvs2svn/branches/MSMITH/usr.sbin/mlxcontrol/interface.c 59138 2000-04-11 03:01:45Z msmith $
27251655Sadrian */
28251655Sadrian
29251655Sadrian#include <fcntl.h>
30251655Sadrian#include <stdio.h>
31251655Sadrian#include <stdlib.h>
32251655Sadrian#include <unistd.h>
33251655Sadrian#include <string.h>
34251655Sadrian#include <cam/scsi/scsi_all.h>
35251655Sadrian
36251655Sadrian#if 0
37251655Sadrian#include <sys/mlxio.h>
38251655Sadrian#include <sys/mlxreg.h>
39251655Sadrian#else
40251655Sadrian#include "../sys/dev/mlx/mlxio.h"
41251655Sadrian#include "../sys/dev/mlx/mlxreg.h"
42251655Sadrian#endif
43251655Sadrian
44251655Sadrian#include "mlxcontrol.h"
45251655Sadrian
46251655Sadrian/********************************************************************************
47251655Sadrian * Iterate over all mlx devices, call (func) with each ones' path and (arg)
48251655Sadrian */
49251655Sadrianvoid
50251655Sadrianmlx_foreach(void (*func)(int unit, void *arg), void *arg)
51251655Sadrian{
52251655Sadrian    int		i, fd;
53251655Sadrian
54251655Sadrian    /* limit total count for sanity */
55251655Sadrian    for (i = 0; i < 64; i++) {
56251655Sadrian	/* verify we can open it */
57251655Sadrian	if ((fd = open(ctrlrpath(i), 0)) >= 0)
58251655Sadrian	    close(fd);
59251655Sadrian	/* if we can, do */
60251655Sadrian	if (fd >= 0) {
61251655Sadrian	    func(i, arg);
62251655Sadrian	}
63251655Sadrian    }
64251655Sadrian}
65251655Sadrian
66251655Sadrian/********************************************************************************
67251655Sadrian * Open the controller (unit) and give the fd to (func) along with (arg)
68251655Sadrian */
69251655Sadrianvoid
70251655Sadrianmlx_perform(int unit, void (*func)(int fd, void *arg), void *arg)
71251655Sadrian{
72251655Sadrian    int		fd;
73251655Sadrian
74251655Sadrian    if ((fd = open(ctrlrpath(unit), 0)) >= 0) {
75251655Sadrian	func(fd, arg);
76251655Sadrian	close(fd);
77251655Sadrian    }
78251655Sadrian}
79251655Sadrian
80251655Sadrian/********************************************************************************
81251655Sadrian * Iterate over all mlxd devices, call (func) with each ones' path and (arg)
82251655Sadrian */
83251655Sadrianvoid
84251655Sadrianmlxd_foreach_ctrlr(int unit, void *arg)
85251655Sadrian{
86251655Sadrian    struct mlxd_foreach_action	*ma = (struct mlxd_foreach_action *)arg;
87251655Sadrian    int				i, fd;
88251655Sadrian
89251655Sadrian    /* Get the device */
90251655Sadrian    if ((fd = open(ctrlrpath(unit), 0)) < 0)
91251730Sadrian	return;
92251655Sadrian
93251655Sadrian    for (i = -1; ;) {
94251655Sadrian	/* Get the unit number of the next child device */
95251655Sadrian	if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0)
96251655Sadrian	    return;
97251655Sadrian
98251655Sadrian	/* check that we can open this unit */
99251655Sadrian	if ((fd = open(drivepath(i), 0)) >= 0)
100251655Sadrian	    close(fd);
101251655Sadrian	/* if we can, do */
102251655Sadrian	if (fd >= 0) {
103251655Sadrian	    ma->func(i, ma->arg);
104251655Sadrian	}
105251655Sadrian    }
106251730Sadrian}
107251730Sadrian
108251730Sadrianvoid
109251730Sadrianmlxd_foreach(void (*func)(int unit, void *arg), void *arg)
110251730Sadrian{
111251730Sadrian    struct mlxd_foreach_action ma;
112251730Sadrian
113251730Sadrian    ma.func = func;
114251730Sadrian    ma.arg = arg;
115251730Sadrian    mlx_foreach(mlxd_foreach_ctrlr, &ma);
116251730Sadrian}
117251730Sadrian
118251655Sadrian/********************************************************************************
119251655Sadrian * Find the controller that manages the drive (unit), return controller number
120251655Sadrian * and system drive number on that controller.
121251655Sadrian */
122251655Sadrianstatic struct
123251655Sadrian{
124251655Sadrian    int		unit;
125251655Sadrian    int		ctrlr;
126251655Sadrian    int		sysdrive;
127251655Sadrian} mlxd_find_ctrlr_param;
128251655Sadrian
129251655Sadrianstatic void
130251655Sadrianmlxd_find_ctrlr_search(int unit, void *arg)
131251655Sadrian{
132251655Sadrian    int				i, fd;
133251655Sadrian
134251655Sadrian    /* Get the device */
135251655Sadrian    if ((fd = open(ctrlrpath(unit), 0)) >= 0) {
136251655Sadrian	for (i = -1; ;) {
137251655Sadrian	    /* Get the unit number of the next child device */
138251655Sadrian	    if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0)
139251655Sadrian		break;
140251655Sadrian
141251655Sadrian	    /* is this child the unit we want? */
142251655Sadrian	    if (i == mlxd_find_ctrlr_param.unit) {
143251655Sadrian		mlxd_find_ctrlr_param.ctrlr = unit;
144251655Sadrian		if (ioctl(fd, MLX_GET_SYSDRIVE, &i) == 0)
145251655Sadrian		    mlxd_find_ctrlr_param.sysdrive = i;
146251655Sadrian	    }
147251655Sadrian	}
148251655Sadrian	close(fd);
149251655Sadrian    }
150251655Sadrian}
151251655Sadrian
152251655Sadrianint
153251655Sadrianmlxd_find_ctrlr(int unit, int *ctrlr, int *sysdrive)
154251655Sadrian{
155251655Sadrian    mlxd_find_ctrlr_param.unit = unit;
156251655Sadrian    mlxd_find_ctrlr_param.ctrlr = -1;
157251655Sadrian    mlxd_find_ctrlr_param.sysdrive = -1;
158251655Sadrian
159251655Sadrian    mlx_foreach(mlxd_find_ctrlr_search, NULL);
160251655Sadrian    if ((mlxd_find_ctrlr_param.ctrlr != -1) && (mlxd_find_ctrlr_param.sysdrive != -1)) {
161251655Sadrian	*ctrlr = mlxd_find_ctrlr_param.ctrlr;
162251655Sadrian	*sysdrive = mlxd_find_ctrlr_param.sysdrive;
163251655Sadrian	return(0);
164251655Sadrian    }
165251655Sadrian    return(1);
166251655Sadrian}
167251655Sadrian
168251655Sadrian
169251655Sadrian/********************************************************************************
170251655Sadrian * Send a command to the controller on (fd)
171251655Sadrian */
172251655Sadrian
173251655Sadrianvoid
174251655Sadrianmlx_command(int fd, void *arg)
175251655Sadrian{
176251655Sadrian    struct mlx_usercommand	*cmd = (struct mlx_usercommand *)arg;
177251655Sadrian    int				error;
178251655Sadrian
179251655Sadrian    error = ioctl(fd, MLX_COMMAND, cmd);
180251655Sadrian    if (error != 0)
181251655Sadrian	cmd->mu_error = error;
182251655Sadrian}
183251655Sadrian
184251655Sadrian/********************************************************************************
185251655Sadrian * Perform an ENQUIRY2 command and return information related to the controller
186251655Sadrian * (unit)
187251655Sadrian */
188251655Sadrianint
189251655Sadrianmlx_enquiry(int unit, struct mlx_enquiry2 *enq)
190251655Sadrian{
191251655Sadrian    struct mlx_usercommand	cmd;
192251655Sadrian
193251655Sadrian    /* build the command */
194251655Sadrian    cmd.mu_datasize = sizeof(*enq);
195251655Sadrian    cmd.mu_buf = enq;
196251655Sadrian    cmd.mu_bufptr = 8;
197251655Sadrian    cmd.mu_command[0] = MLX_CMD_ENQUIRY2;
198251655Sadrian
199251655Sadrian    /* hand it off for processing */
200251655Sadrian    mlx_perform(unit, mlx_command, (void *)&cmd);
201251655Sadrian
202251655Sadrian    return(cmd.mu_status != 0);
203251655Sadrian}
204251655Sadrian
205251655Sadrian
206251655Sadrian/********************************************************************************
207251655Sadrian * Perform a READ CONFIGURATION command and return information related to the controller
208251655Sadrian * (unit)
209251655Sadrian */
210251655Sadrianint
211251655Sadrianmlx_read_configuration(int unit, struct mlx_core_cfg *cfg)
212251655Sadrian{
213251655Sadrian    struct mlx_usercommand	cmd;
214251655Sadrian
215251655Sadrian    /* build the command */
216251655Sadrian    cmd.mu_datasize = sizeof(*cfg);
217251655Sadrian    cmd.mu_buf = cfg;
218251655Sadrian    cmd.mu_bufptr = 8;
219251655Sadrian    cmd.mu_command[0] = MLX_CMD_READ_CONFIG;
220251655Sadrian
221251655Sadrian    /* hand it off for processing */
222251655Sadrian    mlx_perform(unit, mlx_command, (void *)&cmd);
223251655Sadrian
224251655Sadrian    return(cmd.mu_status != 0);
225251655Sadrian}
226251655Sadrian
227251655Sadrian/********************************************************************************
228251655Sadrian * Perform a SCSI INQUIRY command and return pointers to the relevant data.
229251655Sadrian */
230251655Sadrianint
231251655Sadrianmlx_scsi_inquiry(int unit, int channel, int target, char **vendor, char **device, char **revision)
232251655Sadrian{
233251655Sadrian    struct mlx_usercommand	cmd;
234251655Sadrian    static struct {
235251655Sadrian	    struct mlx_dcdb		dcdb;
236251655Sadrian	    union {
237251655Sadrian		struct scsi_inquiry_data	inq;
238251655Sadrian		u_int8_t			pad[SHORT_INQUIRY_LENGTH];
239251655Sadrian	    } d;
240251655Sadrian    } __attribute__ ((packed))		dcdb_cmd;
241251655Sadrian    struct scsi_inquiry		*inq_cmd = (struct scsi_inquiry *)&dcdb_cmd.dcdb.dcdb_cdb[0];
242251655Sadrian
243251655Sadrian    /* build the command */
244251655Sadrian    cmd.mu_datasize = sizeof(dcdb_cmd);
245251655Sadrian    cmd.mu_buf = &dcdb_cmd;
246251655Sadrian    cmd.mu_command[0] = MLX_CMD_DIRECT_CDB;
247251655Sadrian
248251655Sadrian    /* build the DCDB */
249251655Sadrian    bzero(&dcdb_cmd, sizeof(dcdb_cmd));
250251655Sadrian    dcdb_cmd.dcdb.dcdb_channel = channel;
251251655Sadrian    dcdb_cmd.dcdb.dcdb_target = target;
252251655Sadrian    dcdb_cmd.dcdb.dcdb_flags = MLX_DCDB_DATA_IN | MLX_DCDB_TIMEOUT_10S;
253251655Sadrian    dcdb_cmd.dcdb.dcdb_datasize = SHORT_INQUIRY_LENGTH;
254251655Sadrian    dcdb_cmd.dcdb.dcdb_cdb_length = 6;
255251655Sadrian    dcdb_cmd.dcdb.dcdb_sense_length = SSD_FULL_SIZE;
256251655Sadrian
257251655Sadrian    /* build the cdb */
258251655Sadrian    inq_cmd->opcode = INQUIRY;
259251655Sadrian    inq_cmd->length = SHORT_INQUIRY_LENGTH;
260251655Sadrian
261251655Sadrian    /* hand it off for processing */
262251655Sadrian    mlx_perform(unit, mlx_command, &cmd);
263251655Sadrian
264251655Sadrian    if (cmd.mu_status == 0) {
265251655Sadrian	*vendor = &dcdb_cmd.d.inq.vendor[0];
266251655Sadrian	*device = &dcdb_cmd.d.inq.product[0];
267251655Sadrian	*revision = &dcdb_cmd.d.inq.revision[0];
268251655Sadrian    }
269251655Sadrian    return(cmd.mu_status);
270251655Sadrian}
271251655Sadrian
272251655Sadrian/********************************************************************************
273251655Sadrian * Perform a GET DEVICE STATE command and return pointers to the relevant data.
274251655Sadrian */
275251655Sadrianint
276251655Sadrianmlx_get_device_state(int unit, int channel, int target, struct mlx_phys_drv *drv)
277251655Sadrian{
278251655Sadrian    struct mlx_usercommand	cmd;
279251655Sadrian
280251655Sadrian    /* build the command */
281251655Sadrian    cmd.mu_datasize = sizeof(*drv);
282251655Sadrian    cmd.mu_buf = drv;
283251655Sadrian    cmd.mu_bufptr = 8;
284251655Sadrian    cmd.mu_command[0] = MLX_CMD_DEVICE_STATE;
285251655Sadrian    cmd.mu_command[2] = channel;
286251655Sadrian    cmd.mu_command[3] = target;
287251655Sadrian
288251655Sadrian    /* hand it off for processing */
289251655Sadrian    mlx_perform(unit, mlx_command, (void *)&cmd);
290251655Sadrian
291251655Sadrian    return(cmd.mu_status != 0);
292251655Sadrian}
293251655Sadrian