2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-2000 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: scsi-cam.c,v 1.15 2006/05/25 01:47:07 johnfranks Exp $
29 * Interface to execute SCSI commands on an system with cam support
30 * Current support is for FreeBSD 4.x
32 * Copyright (c) Thomes Hepper th@ant.han.de
42 #include <cam/scsi/scsi_message.h>
44 #ifdef HAVE_SYS_MTIO_H
48 #include <scsi-defs.h>
50 extern OpenFiles_T *pChangerDev;
51 extern OpenFiles_T *pTapeDev;
52 extern OpenFiles_T *pTapeDevCtl;
53 extern FILE *debug_file;
56 void SCSI_OS_Version()
59 static char rcsid[] = "$Id: scsi-cam.c,v 1.15 2006/05/25 01:47:07 johnfranks Exp $";
60 DebugPrint(DEBUG_INFO, SECTION_INFO, "scsi-os-layer: %s\n",rcsid);
64 /* parse string of format 1:2:3 and fill in path, target, lun
65 returns 0 if it doesn't look like btl
66 returns 1 if parse successful
67 calls ChgExit if it looks like btl but formatted improperly
70 int parse_btl(char *DeviceName,
71 path_id_t *path, target_id_t *target, lun_id_t *lun)
74 if (strstr(DeviceName, ":") == NULL)
77 p = strtok(DeviceName, ":");
78 if (sscanf(p,"%d", path) != 1) {
80 ChgExit("SCSI_OpenDevice",
81 _("Path conversion error. Digits expected"), FATAL);
84 if ((p = strtok(NULL,":")) == NULL) {
86 ChgExit("SCSI_OpenDevice", _("target in Device Name not found"), FATAL);
89 if (sscanf(p,"%d", target) != 1) {
91 ChgExit("SCSI_OpenDevice",
92 _("Target conversion error. Digits expected"), FATAL);
95 if ((p = strtok(NULL,":")) == NULL) {
97 ChgExit("SCSI_OpenDevice", _("lun in Device Name not found"), FATAL);
99 if (sscanf(p,"%d", lun) != 1) {
101 ChgExit("SCSI_OpenDevice",
102 _("LUN conversion error. Digits expected"), FATAL);
109 * Check if the device is already open,
110 * if no open it and save it in the list
112 * DeviceName can be an device name, /dev/nrsa0 for example
113 * or an bus:target:lun path, 0:4:0 for bus 0 target 4 lun 0
116 int SCSI_OpenDevice(int ip)
118 extern OpenFiles_T *pDev;
126 DeviceName = stralloc(pDev[ip].dev);
128 if (pDev[ip].inqdone == 0) {
129 pDev[ip].inqdone = 1;
131 pDev[ip].inquiry = (SCSIInquiry_T *)malloc(INQUIRY_SIZE);
132 if (parse_btl(DeviceName, &path, &target, &lun))
133 pDev[ip].curdev = cam_open_btl(path, target, lun, O_RDWR, NULL);
135 pDev[ip].curdev = cam_open_device(DeviceName, O_RDWR);
138 if (pDev[ip].curdev) {
141 pDev[ip].devopen = 1;
142 if (SCSI_Inquiry(ip, pDev[ip].inquiry, INQUIRY_SIZE) == 0) {
143 if (pDev[ip].inquiry->type == TYPE_TAPE || pDev[ip].inquiry->type == TYPE_CHANGER) {
145 pDev[ip].ident[i] = pDev[ip].inquiry->prod_ident[i];
147 for (i=15; i >= 0 && !isalnum(pDev[ip].ident[i]); i--) {
148 pDev[ip].ident[i] = '\0';
152 if (pDev[ip].inquiry->type == TYPE_TAPE)
154 pDev[ip].type = stralloc("tape");
157 if (pDev[ip].inquiry->type == TYPE_CHANGER)
159 pDev[ip].type = stralloc("changer");
162 PrintInquiry(pDev[ip].inquiry);
165 free(pDev[ip].inquiry);
170 free(pDev[ip].inquiry);
171 pDev[ip].inquiry = NULL;
174 } else { /* Device open failed */
175 DebugPrint(DEBUG_INFO, SECTION_SCSI,_("##### STOP SCSI_OpenDevice open failed\n"));
179 if (parse_btl(DeviceName, &path, &target, &lun))
180 pDev[ip].curdev = cam_open_btl(path, target, lun, O_RDWR, NULL);
182 pDev[ip].curdev = cam_open_device(DeviceName, O_RDWR);
186 if (pDev[ip].curdev) {
187 pDev[ip].devopen = 1;
194 int SCSI_CloseDevice(int DeviceFD)
197 extern OpenFiles_T *pDev;
199 if (pDev[DeviceFD].SCSI == 1)
201 cam_close_device(pDev[DeviceFD].curdev);
202 pDev[DeviceFD].devopen = 0;
204 close(pDev[DeviceFD].fd);
209 int SCSI_ExecuteCommand(int DeviceFD,
210 Direction_T Direction,
214 size_t DataBufferLength,
215 RequestSense_T *pRequestSense,
216 size_t RequestSenseLength)
218 ExtendedRequestSense_T ExtendedRequestSense;
219 extern OpenFiles_T *pDev;
223 OpenFiles_T *pwork = NULL;
225 /* Basic sanity checks */
226 assert(CDB_Length <= UCHAR_MAX);
227 assert(RequestSenseLength <= UCHAR_MAX);
229 /* Clear buffer for cases where sense is not returned */
230 memset(pRequestSense, 0, RequestSenseLength);
232 if (pDev[DeviceFD].avail == 0)
238 * CLear the SENSE buffer
240 bzero(pRequestSense, RequestSenseLength);
242 DecodeSCSI(CDB, "SCSI_ExecuteCommand : ");
244 ccb = cam_getccb(pDev[DeviceFD].curdev);
247 bzero(&(&ccb->ccb_h)[1], SIZEOF(struct ccb_scsiio));
248 bcopy(&CDB[0], &ccb->csio.cdb_io.cdb_bytes, CDB_Length);
253 if (DataBufferLength == 0)
255 ccb_flags = CAM_DIR_NONE;
257 ccb_flags = CAM_DIR_IN;
261 if (DataBufferLength == 0)
263 ccb_flags = CAM_DIR_NONE;
265 ccb_flags = CAM_DIR_OUT;
269 ccb_flags = CAM_DIR_NONE;
273 cam_fill_csio(&ccb->csio,
276 /* flags */ ccb_flags,
277 /* tag_action */ MSG_SIMPLE_Q_TAG,
278 /* data_ptr */ (guint8*)DataBuffer,
279 /* dxfer_len */ DataBufferLength,
280 /* sense_len */ SSD_FULL_SIZE,
281 /* cdb_len */ CDB_Length,
282 /* timeout */ 600 * 1000);
285 if (pDev[DeviceFD].devopen == 0)
287 if (SCSI_OpenDevice(DeviceFD) == 0)
294 ret = cam_send_ccb(pDev[DeviceFD].curdev, ccb);
295 SCSI_CloseDevice(DeviceFD);
304 * copy the SENSE data to the Sense Buffer !!
306 memcpy(pRequestSense, &ccb->csio.sense_data, RequestSenseLength);
308 /* ToDo add error handling */
309 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
311 dbprintf(_("SCSI_ExecuteCommand return %d\n"), (ccb->ccb_h.status & CAM_STATUS_MASK));
320 * Send the command to the device with the
323 int Tape_Ioctl( int DeviceFD, int command)
325 extern OpenFiles_T *pDev;
329 if (pDev[DeviceFD].devopen == 0)
330 if (SCSI_OpenDevice(DeviceFD) == 0)
343 if (ioctl(pDev[DeviceFD].fd , MTIOCTOP, &mtop) != 0)
345 dbprintf(_("Tape_Ioctl error ioctl %s\n"), strerror(errno));
346 SCSI_CloseDevice(DeviceFD);
350 SCSI_CloseDevice(DeviceFD);
354 int Tape_Status( int DeviceFD)
356 extern OpenFiles_T *pDev;
360 if (pDev[DeviceFD].devopen == 0)
361 if (SCSI_OpenDevice(DeviceFD) == 0)
364 if (ioctl(pDev[DeviceFD].fd , MTIOCGET, &mtget) != 0)
366 dbprintf(_("Tape_Status error ioctl %s\n"), strerror(errno));
367 SCSI_CloseDevice(DeviceFD);
371 dbprintf("ioctl -> mtget.mt_dsreg %lX\n",mtget.mt_dsreg);
372 dbprintf("ioctl -> mtget.mt_erreg %lX\n",mtget.mt_erreg);
375 * I have no idea what is the meaning of the bits in mt_erreg
376 * I assume that nothing set is tape loaded
377 * 0x2 is no tape online
379 if (mtget.mt_erreg == 0)
381 ret = ret | TAPE_ONLINE;
384 if (mtget.mt_erreg & 0x2)
386 ret = ret | TAPE_NOT_LOADED;
389 SCSI_CloseDevice(DeviceFD);
394 * Scans the bus for device with the type 'tape' or 'robot'
397 int ScanBus(int print)
401 extern OpenFiles_T *pDev;
403 for (bus = 0;bus < 3; bus++)
405 pDev[count].dev = malloc(10);
406 for (target = 0;target < 8; target++)
408 for (lun = 0; lun < 8; lun++)
410 g_sprintf(pDev[count].dev, "%d:%d:%d", bus, target, lun);
411 pDev[count].inqdone = 0;
412 if (OpenDevice(count, pDev[count].dev, "Scan", NULL))
414 if (pDev[count].inquiry->type == TYPE_TAPE ||
415 pDev[count].inquiry->type == TYPE_CHANGER)
418 pDev[count].dev = malloc(10);
422 g_printf(_("bus:target:lun -> %s == "),pDev[count].dev);
424 switch (pDev[count].inquiry->type)
433 g_printf(_("Printer"));
436 g_printf(_("Processor"));
442 g_printf(_("Cdrom"));
445 g_printf(_("Scanner"));
448 g_printf(_("Optical"));
451 g_printf(_("Changer"));
457 g_printf(_("unknown %d"),pDev[count].inquiry->type);
472 * indent-tabs-mode: nil