1 /*
2  * Copyright (c) 1998,2001
3  *      Traakan, Inc., Los Altos, CA
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *      This contains the O/S (Operating System) specific
35  *      portions of NDMJOBLIB for the FreeBSD platform.
36  *
37  *      This file is #include'd by ndmos.c when
38  *      selected by #ifdef's of NDMOS_ID.
39  *
40  *      There are four major portions:
41  *      1) Misc support routines: password check, local info, etc
42  *      2) Non-blocking I/O support routines
43  *      3) Tape interfacs ndmos_tape_xxx()
44  *      4) OS Specific NDMP request dispatcher which intercepts
45  *         requests implemented here, such as SCSI operations
46  *         and system configuration queries.
47  */
48 
49 
50 /*
51  * #include "ndmagents.h" already done in ndmos.c
52  * Additional #include's, not needed in ndmos_freebsd.h, yet needed here.
53  */
54 #include <sys/utsname.h>
55 #include <camlib.h>
56 #include <cam/scsi/scsi_message.h>
57 
58 
59 /*
60  * Select common code fragments from ndmos_common.c
61  */
62 #define NDMOS_COMMON_SYNC_CONFIG_INFO /* from config file (ndmjob.conf) */
63 #define NDMOS_COMMON_OK_NAME_PASSWORD
64 #define NDMOS_COMMON_MD5
65 #define NDMOS_COMMON_NONBLOCKING_IO_SUPPORT
66 #define NDMOS_COMMON_TAPE_INTERFACE   /* uses tape simulator */
67 #define NDMOS_COMMON_SCSI_INTERFACE   /* use scsi simulator */
68 #define NDMOS_COMMON_DISPATCH_REQUEST /* no-op */
69 
70 
71 #include "ndmos_common.c"
72 
73 #ifdef NDMOS_COMMON_SCSI_INTERFACE
74 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT /* Surrounds all SCSI intfs */
75 #ifndef NDMOS_OPTION_ROBOT_SIMULATOR
76 /*
77  * SCSI INTERFACE
78  ****************************************************************
79  */
80 
ndmos_scsi_initialize(struct ndm_session * sess)81 int ndmos_scsi_initialize(struct ndm_session* sess)
82 {
83   sess->robot_acb->camdev = 0;
84   return 0;
85 }
86 
ndmos_scsi_sync_state(struct ndm_session * sess)87 void ndmos_scsi_sync_state(struct ndm_session* sess)
88 {
89   struct ndm_robot_agent* robot = sess->robot_acb;
90   struct cam_device* camdev = robot->camdev;
91   ndmp9_scsi_get_state_reply* state = &robot->scsi_state;
92 
93   if (robot->camdev) {
94     state->error = NDMP9_NO_ERR;
95     state->target_controller = camdev->path_id;
96     state->target_id = camdev->target_id;
97     state->target_lun = camdev->target_lun;
98   } else {
99     state->error = NDMP9_DEV_NOT_OPEN_ERR;
100     state->target_controller = -1;
101     state->target_id = -1;
102     state->target_lun = -1;
103   }
104 }
105 
ndmos_scsi_open(struct ndm_session * sess,char * name)106 ndmp9_error ndmos_scsi_open(struct ndm_session* sess, char* name)
107 {
108   struct ndm_robot_agent* robot = sess->robot_acb;
109   struct cam_device* camdev = robot->camdev;
110 
111   /* redundant test */
112   if (camdev) { return NDMP9_DEVICE_OPENED_ERR; }
113 
114   camdev = cam_open_pass(name, 2, 0);
115   if (!camdev) {
116     /* could sniff errno */
117     switch (errno) {
118       default:
119       case ENOENT:
120         return NDMP9_NO_DEVICE_ERR;
121 
122       case EACCES:
123       case EPERM:
124         return NDMP9_PERMISSION_ERR;
125 
126       case EBUSY:
127         return NDMP9_DEVICE_BUSY_ERR;
128     }
129   }
130 
131   robot->camdev = camdev;
132   ndmos_scsi_sync_state(sess);
133 
134   return NDMP9_NO_ERR;
135 }
136 
ndmos_scsi_close(struct ndm_session * sess)137 ndmp9_error ndmos_scsi_close(struct ndm_session* sess)
138 {
139   struct ndm_robot_agent* robot = sess->robot_acb;
140   struct cam_device* camdev = robot->camdev;
141 
142   /* redundant test */
143   if (!camdev) { return NDMP9_DEV_NOT_OPEN_ERR; }
144 
145   robot->camdev = 0;
146   ndmos_scsi_sync_state(sess);
147 
148   cam_close_device(camdev);
149 
150   return NDMP9_NO_ERR;
151 }
152 
153 /* deprecated */
ndmos_scsi_set_target(struct ndm_session * sess)154 ndmp9_error ndmos_scsi_set_target(struct ndm_session* sess)
155 {
156   return NDMP9_NOT_SUPPORTED_ERR;
157 }
158 
ndmos_scsi_reset_device(struct ndm_session * sess)159 ndmp9_error ndmos_scsi_reset_device(struct ndm_session* sess)
160 {
161   return NDMP9_NOT_SUPPORTED_ERR;
162 }
163 
164 /* deprecated */
ndmos_scsi_reset_bus(struct ndm_session * sess)165 ndmp9_error ndmos_scsi_reset_bus(struct ndm_session* sess)
166 {
167   return NDMP9_NOT_SUPPORTED_ERR;
168 }
169 
ndmos_scsi_execute_cdb(struct ndm_session * sess,ndmp9_execute_cdb_request * request,ndmp9_execute_cdb_reply * reply)170 ndmp9_error ndmos_scsi_execute_cdb(struct ndm_session* sess,
171                                    ndmp9_execute_cdb_request* request,
172                                    ndmp9_execute_cdb_reply* reply)
173 {
174   struct ndm_robot_agent* robot = sess->robot_acb;
175   struct cam_device* camdev = robot->camdev;
176   union ccb* ccb;
177   uint32_t flags;
178   uint8_t* data_ptr = 0;
179   uint8_t* data_in_ptr = 0;
180   uint32_t data_len = 0;
181   uint32_t data_done;
182   int rc;
183 
184   NDMOS_MACRO_ZEROFILL(reply);
185   reply->error = NDMP9_IO_ERR; /* pessimistic */
186 
187   ccb = cam_getccb(camdev);
188 
189   if (!ccb) {
190     reply->error = NDMP9_NO_MEM_ERR;
191     return reply->error;
192   }
193 
194   switch (request->data_dir) {
195     case NDMP9_SCSI_DATA_DIR_NONE:
196       flags = CAM_DIR_NONE;
197       break;
198 
199     case NDMP9_SCSI_DATA_DIR_IN:
200       if (data_len > 1024 * 1024) {
201         reply->error = NDMP9_ILLEGAL_ARGS_ERR;
202         goto out;
203       }
204 
205       data_len = request->datain_len;
206       data_in_ptr = (uint8_t*)malloc(data_len);
207 
208       if (!data_in_ptr) {
209         reply->error = NDMP9_NO_MEM_ERR;
210         goto out;
211       }
212       data_ptr = data_in_ptr;
213       flags = CAM_DIR_IN;
214       break;
215 
216     case NDMP9_SCSI_DATA_DIR_OUT:
217       data_len = request->dataout.dataout_len;
218       data_ptr = (uint8_t*)request->dataout.dataout_val;
219       flags = CAM_DIR_OUT;
220       break;
221 
222     default:
223       return NDMP9_ILLEGAL_ARGS_ERR;
224       break;
225   }
226 
227   bcopy(request->cdb.cdb_val, &ccb->csio.cdb_io.cdb_bytes,
228         request->cdb.cdb_len);
229 
230   cam_fill_csio(&ccb->csio,
231                 /*retries*/ 1,
232                 /*cbfcnp*/ NULL,
233                 /*flags*/ flags,
234                 /*tag_action*/ MSG_SIMPLE_Q_TAG,
235                 /*data_ptr*/ data_ptr,
236                 /*dxfer_len*/ data_len,
237                 /*sense_len*/ SSD_FULL_SIZE,
238                 /*cdb_len*/ request->cdb.cdb_len,
239                 /*timeout*/ request->timeout);
240 
241   rc = cam_send_ccb(camdev, ccb);
242   if (rc != 0) {
243     reply->error = NDMP9_IO_ERR;
244     goto out;
245   }
246 
247   switch (ccb->csio.ccb_h.status & CAM_STATUS_MASK) {
248     case CAM_REQ_CMP: /* completed */
249       reply->error = NDMP9_NO_ERR;
250       break;
251 
252     case CAM_SEL_TIMEOUT:
253     case CAM_CMD_TIMEOUT:
254       reply->error = NDMP9_TIMEOUT_ERR;
255       break;
256 
257     case CAM_SCSI_STATUS_ERROR:
258       if (ccb->csio.ccb_h.status & CAM_AUTOSNS_VALID) {
259         int n_sense;
260 
261         n_sense = ccb->csio.sense_len - ccb->csio.sense_resid;
262         reply->ext_sense.ext_sense_val = (char*)malloc(n_sense);
263         if (reply->ext_sense.ext_sense_val) {
264           bcopy(&ccb->csio.sense_data, reply->ext_sense.ext_sense_val, n_sense);
265           reply->ext_sense.ext_sense_len = n_sense;
266         }
267       }
268       reply->error = NDMP9_NO_ERR;
269       break;
270 
271     default:
272       reply->error = NDMP9_IO_ERR;
273       break;
274   }
275 
276 out:
277   if (reply->error == NDMP9_NO_ERR) {
278     reply->status = ccb->csio.scsi_status;
279     data_done = data_len - ccb->csio.resid;
280 
281     switch (request->data_dir) {
282       case NDMP9_SCSI_DATA_DIR_NONE:
283         break;
284 
285       case NDMP9_SCSI_DATA_DIR_IN:
286         reply->datain.datain_val = (char*)data_in_ptr;
287         reply->datain.datain_len = data_len;
288         break;
289 
290       case NDMP9_SCSI_DATA_DIR_OUT:
291         reply->dataout_len = data_len;
292         break;
293 
294       default:
295         break;
296     }
297   } else {
298     if (data_in_ptr) {
299       free(data_in_ptr);
300       data_in_ptr = 0;
301     }
302   }
303 
304   cam_freeccb(ccb);
305 
306   return reply->error;
307 }
308 #endif /* NDMOS_OPTION_ROBOT_SIMULATOR */
309 #endif /* NDMOS_OPTION_NO_ROBOT_AGENT   Surrounds all SCSI intfs */
310 #endif /* NDMOS_COMMON_SCSI_INTERFACE */
311