1 /* cdrdao - write audio CD-Rs in disc-at-once mode
2 *
3 * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 /* SCSI interface implemenation for FreeBSD.
21 * Written by Max Khon <fjoe@iclub.nsu.ru>
22 */
23
24 #include <config.h>
25
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include <camlib.h>
31 #include <bus/cam/scsi/scsi_message.h>
32
33 #include "ScsiIf.h"
34 #include "log.h"
35 #include "util.h"
36
37 #define DEF_RETRY_COUNT 1
38
39 #include "decodeSense.cc"
40
41 class ScsiIfImpl {
42 public:
43 char * devname;
44 struct cam_device * dev;
45 union ccb * ccb;
46 int timeout; /* timeout in ms */
47 };
48
ScsiIf(const char * devname)49 ScsiIf::ScsiIf(const char *devname)
50 {
51 impl_ = new ScsiIfImpl;
52 impl_->devname = strdupCC(devname);
53 impl_->dev = NULL;
54 impl_->ccb = NULL;
55 impl_->timeout = 5000;
56
57 maxDataLen_ = 32 * 1024;
58 vendor_[0] = 0;
59 product_[0] = 0;
60 revision_[0] = 0;
61 }
62
~ScsiIf()63 ScsiIf::~ScsiIf()
64 {
65 if (impl_->ccb)
66 cam_freeccb(impl_->ccb);
67 if (impl_->dev)
68 cam_close_device(impl_->dev);
69 delete[] impl_->devname;
70 delete impl_;
71 }
72
73 // opens scsi device
74 // return: 0: OK
75 // 1: device could not be opened
76 // 2: inquiry failed
init()77 int ScsiIf::init()
78 {
79 if ((impl_->dev = cam_open_device(impl_->devname, O_RDWR)) == NULL) {
80 log_message(-2, "%s", cam_errbuf);
81 return 1;
82 }
83
84 impl_->ccb = cam_getccb(impl_->dev);
85 if (impl_->ccb == NULL) {
86 log_message(-2, "init: error allocating ccb");
87 return 1;
88 }
89
90 if (inquiry())
91 return 2;
92
93 return 0;
94 }
95
96 // Sets given timeout value in seconds and returns old timeout.
97 // return: old timeout
timeout(int t)98 int ScsiIf::timeout(int t)
99 {
100 int old = impl_->timeout;
101 impl_->timeout = t*1000;
102 return old/1000;
103 }
104
105 // sends a scsi command and receives data
106 // return 0: OK
107 // 1: scsi command failed (os level, no sense data available)
108 // 2: scsi command failed (sense data available)
sendCmd(const unsigned char * cmd,int cmdLen,const unsigned char * dataOut,int dataOutLen,unsigned char * dataIn,int dataInLen,int showMessage)109 int ScsiIf::sendCmd(const unsigned char *cmd, int cmdLen,
110 const unsigned char *dataOut, int dataOutLen,
111 unsigned char *dataIn, int dataInLen,
112 int showMessage)
113 {
114 int retval;
115 int flags = CAM_DIR_NONE;
116 u_int8_t * data_ptr;
117 size_t data_len;
118
119 bzero(impl_->ccb, sizeof(union ccb));
120 bcopy(cmd, &impl_->ccb->csio.cdb_io.cdb_bytes, cmdLen);
121
122 if (dataOut && dataOutLen > 0) {
123 data_ptr = (u_int8_t*) dataOut;
124 data_len = dataOutLen;
125 flags = CAM_DIR_OUT;
126 }
127 else if (dataIn && dataInLen > 0) {
128 data_ptr = dataIn;
129 data_len = dataInLen;
130 flags = CAM_DIR_IN;
131 }
132
133 cam_fill_csio(&impl_->ccb->csio,
134 DEF_RETRY_COUNT,
135 NULL,
136 flags | CAM_DEV_QFRZDIS,
137 MSG_SIMPLE_Q_TAG,
138 data_ptr,
139 data_len,
140 SSD_FULL_SIZE,
141 cmdLen,
142 impl_->timeout);
143 if ((retval = cam_send_ccb(impl_->dev, impl_->ccb)) < 0
144 || (impl_->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
145 if (retval < 0) {
146 log_message(-2, "sendCmd: error sending command");
147 return 1;
148 }
149
150 if ((impl_->ccb->ccb_h.status & CAM_STATUS_MASK) ==
151 CAM_SCSI_STATUS_ERROR) {
152 if (showMessage)
153 printError();
154
155 return 2;
156 }
157 return 1;
158 }
159
160 return 0;
161 }
162
getSense(int & len) const163 const unsigned char *ScsiIf::getSense(int &len) const
164 {
165 len = impl_->ccb->csio.sense_len;
166 return (const unsigned char*) &impl_->ccb->csio.sense_data;
167 }
168
printError()169 void ScsiIf::printError()
170 {
171 decodeSense((const unsigned char*) &impl_->ccb->csio.sense_data,
172 impl_->ccb->csio.sense_len);
173 }
174
inquiry()175 int ScsiIf::inquiry()
176 {
177 int i;
178 struct scsi_inquiry_data inq_data;
179
180 bzero(impl_->ccb, sizeof(union ccb));
181 bzero(&inq_data, sizeof(inq_data));
182
183 scsi_inquiry(&impl_->ccb->csio,
184 DEF_RETRY_COUNT,
185 NULL,
186 MSG_SIMPLE_Q_TAG,
187 (u_int8_t*) &inq_data,
188 sizeof(inq_data),
189 0,
190 0,
191 SSD_FULL_SIZE,
192 impl_->timeout);
193 impl_->ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
194
195 if (cam_send_ccb(impl_->dev, impl_->ccb) < 0) {
196 if ((impl_->ccb->ccb_h.status & CAM_STATUS_MASK) !=
197 CAM_SCSI_STATUS_ERROR) {
198 log_message(-2, "%s", cam_errbuf);
199 return 1;
200 }
201
202 printError();
203 return 1;
204 }
205
206 strncpy(vendor_, inq_data.vendor, 8);
207 vendor_[8] = 0;
208
209 strncpy(product_, inq_data.product, 16);
210 product_[16] = 0;
211
212 strncpy(revision_, inq_data.revision, 4);
213 revision_[4] = 0;
214
215 for (i = 7; i >= 0 && vendor_[i] == ' '; i--)
216 vendor_[i] = 0;
217
218 for (i = 15; i >= 0 && product_[i] == ' '; i--)
219 product_[i] = 0;
220
221 for (i = 3; i >= 0 && revision_[i] == ' '; i--)
222 revision_[i] = 0;
223
224 return 0;
225 }
226
scan(int * len,char * scsi_dev_path)227 ScsiIf::ScanData *ScsiIf::scan(int *len, char* scsi_dev_path)
228 {
229 *len = 0;
230 return NULL;
231 }
232
233 #include "ScsiIf-common.cc"
234