1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
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.
38 #include <sys/types.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
{
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
72 dump_bytes(guchar
*buf
, gint len
)
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
);
83 dump_cdb(guchar
*cdb
, gint cdblen
)
85 gchar
*out
= dump_bytes(cdb
, cdblen
);
86 DEBUG("CDB:\t%s", out
);
91 * This is to send a command
94 brasero_scsi_command_issue_sync (gpointer command
,
97 BraseroScsiErrCode
*error
)
99 uchar sense_buffer
[BRASERO_SENSE_DATA_SIZE
];
100 struct uscsi_cmd transport
;
103 short timeout
= 4 * 60;
105 memset (&sense_buffer
, 0, BRASERO_SENSE_DATA_SIZE
);
106 memset (&transport
, 0, sizeof (struct uscsi_cmd
));
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
;
148 out
= dump_bytes((char *)transport
.uscsi_rqbuf
, len
);
149 DEBUG("uscsi_rqbuf: %s\n", out
);
152 DEBUG("uscsi_rqbuf: <data not available>\n");
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
;
171 brasero_scsi_command_new (const BraseroScsiCmdInfo
*info
,
172 BraseroDeviceHandle
*handle
)
176 /* make sure we can set the flags of the descriptor */
178 /* allocate the command */
179 cmd
= g_new0 (BraseroScsiCmd
, 1);
181 cmd
->handle
= handle
;
183 BRASERO_SCSI_CMD_SET_OPCODE (cmd
);
188 brasero_scsi_command_free (gpointer cmd
)
191 return BRASERO_SCSI_OK
;
195 * This is to open a device
198 BraseroDeviceHandle
*
199 brasero_device_handle_open (const gchar
*path
,
201 BraseroScsiErrCode
*code
)
204 int flags
= OPEN_FLAGS
;
205 BraseroDeviceHandle
*handle
;
208 /* flags |= O_EXCL; */
210 if (g_str_has_prefix(path
, "/dev/dsk/")) {
212 rawdisk
= g_strdup_printf ("/dev/rdsk/%s", path
+ 9);
213 fd
= open (rawdisk
, flags
);
216 fd
= open (path
, flags
);
222 || errno
== EWOULDBLOCK
224 *code
= BRASERO_SCSI_NOT_READY
;
226 *code
= BRASERO_SCSI_ERRNO
;
229 DEBUG("open ERR: %s\n", g_strerror(errno
));
233 handle
= g_new (BraseroDeviceHandle
, 1);
240 brasero_device_handle_close (BraseroDeviceHandle
*handle
)
247 brasero_device_get_bus_target_lun (const gchar
*device
)
249 return strdup (device
);