Merge branch 'master' into 'master'
[brasero.git] / libbrasero-media / scsi-uscsi.c
blobe78400753862fbfe141d529ebac1dd16b4925cd7
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * Libbrasero-media
4 * Copyright (C) Lin Ma 2008 <lin.ma@sun.com>
6 * Libbrasero-media is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * The Libbrasero-media authors hereby grant permission for non-GPL compatible
12 * GStreamer plugins to be used and distributed together with GStreamer
13 * and Libbrasero-media. This permission is above and beyond the permissions granted
14 * by the GPL license by which Libbrasero-media is covered. If you modify this code
15 * you may extend this exception to your version of the code, but you are not
16 * obligated to do so. If you do not wish to do so, delete this exception
17 * statement from your version.
19 * Libbrasero-media is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to:
26 * The Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor
28 * Boston, MA 02110-1301, USA.
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
35 #include <errno.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <string.h>
43 #include <sys/scsi/scsi.h>
44 #include <sys/scsi/impl/uscsi.h>
46 #include "brasero-media-private.h"
47 #include "scsi-command.h"
48 #include "scsi-utils.h"
49 #include "scsi-error.h"
50 #include "scsi-sense-data.h"
52 #define DEBUG BRASERO_MEDIA_LOG
54 struct _BraseroDeviceHandle {
55 int fd;
58 struct _BraseroScsiCmd {
59 uchar cmd [BRASERO_SCSI_CMD_MAX_LEN];
60 BraseroDeviceHandle *handle;
62 const BraseroScsiCmdInfo *info;
64 typedef struct _BraseroScsiCmd BraseroScsiCmd;
66 #define BRASERO_SCSI_CMD_OPCODE_OFF 0
67 #define BRASERO_SCSI_CMD_SET_OPCODE(command) (command->cmd [BRASERO_SCSI_CMD_OPCODE_OFF] = command->info->opcode)
69 #define OPEN_FLAGS O_RDONLY | O_NONBLOCK
71 gchar *
72 dump_bytes(guchar *buf, gint len)
74 GString *out;
75 out = g_string_new("");
76 for(;len > 0; len--) {
77 g_string_append_printf(out, "%02X ", *buf++);
79 return g_string_free(out, FALSE);
82 void
83 dump_cdb(guchar *cdb, gint cdblen)
85 gchar *out = dump_bytes(cdb, cdblen);
86 DEBUG("CDB:\t%s", out);
87 g_free(out);
90 /**
91 * This is to send a command
93 BraseroScsiResult
94 brasero_scsi_command_issue_sync (gpointer command,
95 gpointer buffer,
96 int size,
97 BraseroScsiErrCode *error)
99 uchar sense_buffer [BRASERO_SENSE_DATA_SIZE];
100 struct uscsi_cmd transport;
101 int res;
102 BraseroScsiCmd *cmd;
103 short timeout = 4 * 60;
105 memset (&sense_buffer, 0, BRASERO_SENSE_DATA_SIZE);
106 memset (&transport, 0, sizeof (struct uscsi_cmd));
108 cmd = command;
110 if (cmd->info->direction & BRASERO_SCSI_READ)
111 transport.uscsi_flags = USCSI_READ;
112 else if (cmd->info->direction & BRASERO_SCSI_WRITE)
113 transport.uscsi_flags = USCSI_WRITE;
115 transport.uscsi_cdb = (caddr_t) cmd->cmd;
116 transport.uscsi_cdblen = (uchar_t) cmd->info->size;
117 dump_cdb(transport.uscsi_cdb, transport.uscsi_cdblen);
118 transport.uscsi_bufaddr = (caddr_t) buffer;
119 transport.uscsi_buflen = (size_t) size;
120 transport.uscsi_timeout = timeout;
122 /* where to output the scsi sense buffer */
123 transport.uscsi_flags |= USCSI_RQENABLE | USCSI_SILENT | USCSI_DIAGNOSE;
124 transport.uscsi_rqbuf = sense_buffer;
125 transport.uscsi_rqlen = BRASERO_SENSE_DATA_SIZE;
127 /* NOTE only for TEST UNIT READY, REQUEST/MODE SENSE, INQUIRY, READ
128 * CAPACITY, READ BUFFER, READ and LOG SENSE are allowed with it */
129 res = ioctl (cmd->handle->fd, USCSICMD, &transport);
131 DEBUG("ret: %d errno: %d (%s)", res,
132 res != 0 ? errno : 0,
133 res != 0 ? g_strerror(errno) : "Error 0");
134 DEBUG("uscsi_flags: 0x%x", transport.uscsi_flags);
135 DEBUG("uscsi_status: 0x%x", transport.uscsi_status);
136 DEBUG("uscsi_timeout: %d", transport.uscsi_timeout);
137 DEBUG("uscsi_bufaddr: 0x%lx", (long)transport.uscsi_bufaddr);
138 DEBUG("uscsi_buflen: %d", (int)transport.uscsi_buflen);
139 DEBUG("uscsi_resid: %d", (int)transport.uscsi_resid);
140 DEBUG("uscsi_rqlen: %d", transport.uscsi_rqlen);
141 DEBUG("uscsi_rqstatus: 0x%x", transport.uscsi_rqstatus);
142 DEBUG("uscsi_rqresid: %d", transport.uscsi_rqresid);
143 DEBUG("uscsi_rqbuf ptr: 0x%lx", (long)transport.uscsi_rqbuf);
144 if (transport.uscsi_rqbuf != NULL && transport.uscsi_rqlen > transport.uscsi_rqresid) {
145 int len = transport.uscsi_rqlen - transport.uscsi_rqresid;
146 gchar *out;
148 out = dump_bytes((char *)transport.uscsi_rqbuf, len);
149 DEBUG("uscsi_rqbuf: %s\n", out);
150 g_free(out);
151 } else {
152 DEBUG("uscsi_rqbuf: <data not available>\n");
155 if (res == -1) {
156 BRASERO_SCSI_SET_ERRCODE (error, BRASERO_SCSI_ERRNO);
157 return BRASERO_SCSI_FAILURE;
160 if ((transport.uscsi_status & STATUS_MASK) == STATUS_GOOD)
161 return BRASERO_SCSI_OK;
163 if ((transport.uscsi_rqstatus & STATUS_MASK == STATUS_CHECK)
164 && transport.uscsi_rqlen)
165 return brasero_sense_data_process (sense_buffer, error);
167 return BRASERO_SCSI_FAILURE;
170 gpointer
171 brasero_scsi_command_new (const BraseroScsiCmdInfo *info,
172 BraseroDeviceHandle *handle)
174 BraseroScsiCmd *cmd;
176 /* make sure we can set the flags of the descriptor */
178 /* allocate the command */
179 cmd = g_new0 (BraseroScsiCmd, 1);
180 cmd->info = info;
181 cmd->handle = handle;
183 BRASERO_SCSI_CMD_SET_OPCODE (cmd);
184 return cmd;
187 BraseroScsiResult
188 brasero_scsi_command_free (gpointer cmd)
190 g_free (cmd);
191 return BRASERO_SCSI_OK;
195 * This is to open a device
198 BraseroDeviceHandle *
199 brasero_device_handle_open (const gchar *path,
200 gboolean exclusive,
201 BraseroScsiErrCode *code)
203 int fd;
204 int flags = OPEN_FLAGS;
205 BraseroDeviceHandle *handle;
207 /* if (exclusive) */
208 /* flags |= O_EXCL; */
210 if (g_str_has_prefix(path, "/dev/dsk/")) {
211 gchar *rawdisk;
212 rawdisk = g_strdup_printf ("/dev/rdsk/%s", path + 9);
213 fd = open (rawdisk, flags);
214 g_free(rawdisk);
215 } else {
216 fd = open (path, flags);
219 if (fd < 0) {
220 if (code) {
221 if (errno == EAGAIN
222 || errno == EWOULDBLOCK
223 || errno == EBUSY)
224 *code = BRASERO_SCSI_NOT_READY;
225 else
226 *code = BRASERO_SCSI_ERRNO;
229 DEBUG("open ERR: %s\n", g_strerror(errno));
230 return NULL;
233 handle = g_new (BraseroDeviceHandle, 1);
234 handle->fd = fd;
236 return handle;
239 void
240 brasero_device_handle_close (BraseroDeviceHandle *handle)
242 close (handle->fd);
243 g_free (handle);
246 char *
247 brasero_device_get_bus_target_lun (const gchar *device)
249 return strdup (device);