2 * Copyright 2004-2007, Haiku, Inc. All RightsReserved.
3 * Copyright 2002/03, Thomas Kurschel. All rights reserved.
5 * Distributed under the terms of the MIT License.
11 Scans SCSI busses for devices. Scanning is initiated by
12 a SCSI device node probe (see device_mgr.c)
16 #include "scsi_internal.h"
25 result: true, if device answered
26 false, if there is no device
29 scsi_scan_send_tur(scsi_ccb
*worker_req
)
31 scsi_cmd_tur
*cmd
= (scsi_cmd_tur
*)worker_req
->cdb
;
35 memset( cmd
, 0, sizeof( *cmd
));
36 cmd
->opcode
= SCSI_OP_TEST_UNIT_READY
;
38 worker_req
->sg_list
= NULL
;
39 worker_req
->data
= NULL
;
40 worker_req
->data_length
= 0;
41 worker_req
->cdb_length
= sizeof(*cmd
);
42 worker_req
->timeout
= 0;
43 worker_req
->sort
= -1;
44 worker_req
->flags
= SCSI_DIR_NONE
;
46 scsi_sync_io( worker_req
);
48 SHOW_FLOW( 3, "status=%x", worker_req
->subsys_status
);
50 // as this command was only for syncing, we ignore almost all errors
51 switch (worker_req
->subsys_status
) {
52 case SCSI_SEL_TIMEOUT
:
53 // there seems to be no device around
63 returns true on success
66 scsi_scan_get_inquiry(scsi_ccb
*worker_req
, scsi_res_inquiry
*new_inquiry_data
)
68 scsi_cmd_inquiry
*cmd
= (scsi_cmd_inquiry
*)worker_req
->cdb
;
69 scsi_device_info
*device
= worker_req
->device
;
73 // in case not whole structure gets transferred, we set remaining data to zero
74 memset(new_inquiry_data
, 0, sizeof(*new_inquiry_data
));
76 cmd
->opcode
= SCSI_OP_INQUIRY
;
77 cmd
->lun
= device
->target_lun
;
80 cmd
->allocation_length
= sizeof(*new_inquiry_data
);
82 worker_req
->sg_list
= NULL
;
83 worker_req
->data
= (uchar
*)new_inquiry_data
;
84 worker_req
->data_length
= sizeof(*new_inquiry_data
);
85 worker_req
->cdb_length
= 6;
86 worker_req
->timeout
= SCSI_STD_TIMEOUT
;
87 worker_req
->sort
= -1;
88 worker_req
->flags
= SCSI_DIR_IN
;
90 scsi_sync_io(worker_req
);
92 switch (worker_req
->subsys_status
) {
94 char vendor
[9], product
[17], rev
[5];
96 SHOW_FLOW0(3, "send successfully");
98 // we could check transmission length here, but as we reset
99 // missing bytes before, we get kind of valid data anyway (hopefully)
101 strlcpy(vendor
, new_inquiry_data
->vendor_ident
, sizeof(vendor
));
102 strlcpy(product
, new_inquiry_data
->product_ident
, sizeof(product
));
103 strlcpy(rev
, new_inquiry_data
->product_rev
, sizeof(rev
));
105 SHOW_INFO(3, "device type: %d, qualifier: %d, removable: %d, ANSI version: %d, response data format: %d\n"
106 "vendor: %s, product: %s, rev: %s",
107 new_inquiry_data
->device_type
, new_inquiry_data
->device_qualifier
,
108 new_inquiry_data
->removable_medium
, new_inquiry_data
->ansi_version
,
109 new_inquiry_data
->response_data_format
,
110 vendor
, product
, rev
);
112 SHOW_INFO(3, "additional_length: %d", new_inquiry_data
->additional_length
+ 4);
114 // time to show standards the device conforms to;
115 // unfortunately, ATAPI CD-ROM drives tend to tell that they have
116 // only minimal info (36 bytes), but still they return (valid!) 96 bytes -
118 if (std::min((int)cmd
->allocation_length
,
119 new_inquiry_data
->additional_length
+ 4)
120 >= (int)offsetof(scsi_res_inquiry
, _res74
)) {
121 int i
, previousStandard
= -1;
123 for (i
= 0; i
< 8; ++i
) {
124 int standard
= B_BENDIAN_TO_HOST_INT16(
125 new_inquiry_data
->version_descriptor
[i
]);
127 // omit standards reported twice
128 if (standard
!= previousStandard
&& standard
!= 0)
129 SHOW_INFO(3, "standard: %04x", standard
);
131 previousStandard
= standard
;
140 for( i = 0; i < worker_req->data_length - worker_req->data_resid; ++i ) {
141 dprintf( "%2x ", *((char *)new_inquiry_data + i) );
157 scsi_scan_lun(scsi_bus_info
*bus
, uchar target_id
, uchar target_lun
)
159 scsi_ccb
*worker_req
;
160 scsi_res_inquiry new_inquiry_data
;
162 scsi_device_info
*device
;
167 SHOW_FLOW(3, "%d:%d:%d", bus
->path_id
, target_id
, target_lun
);
169 res
= scsi_force_get_device(bus
, target_id
, target_lun
, &device
);
173 //SHOW_FLOW(3, "temp_device: %d", (int)temp_device);
175 worker_req
= scsi_alloc_ccb(device
);
176 if (worker_req
== NULL
) {
177 // there is no out-of-mem code
184 worker_req
->flags
= SCSI_DIR_IN
;
186 // to give controller a chance to transfer speed negotiation, we
187 // send a TUR first; unfortunatily, some devices don't like TURing
188 // invalid luns apart from lun 0...
189 if (device
->target_lun
== 0) {
190 if (!scsi_scan_send_tur(worker_req
)) {
191 // TBD: need better error code like "device not found"
192 res
= B_NAME_NOT_FOUND
;
197 // get inquiry data to be used as identification
198 // and to check whether there is a device at all
199 found
= scsi_scan_get_inquiry(worker_req
, &new_inquiry_data
)
200 && new_inquiry_data
.device_qualifier
== scsi_periph_qual_connected
;
202 // get rid of temporary device - as soon as the device is
203 // registered, it can be loaded, and we don't want two data
204 // structures for one device (the temporary and the official one)
205 scsi_free_ccb(worker_req
);
206 scsi_put_forced_device(device
);
209 // TBD: better error code, s.a.
210 return B_NAME_NOT_FOUND
;
214 // if a new device is detected on the same connection, all connections
215 // to the old device are disabled;
216 // scenario: you plug in a device, scan the bus, replace the device and then
217 // open it; in this case, the connection seems to be to the old device, but really
218 // is to the new one; if you scan the bus now, the opened connection is disabled
220 // solution 1: scan device during each scsi_init_device
221 // disadvantage: it takes time and we had to submit commands during the load
222 // sequence, which could lead to deadlocks
223 // solution 2: device drivers must scan devices before first use
224 // disadvantage: it takes time and driver must perform a task that
225 // the bus_manager should really take care of
226 res
= scsi_register_device(bus
, target_id
, target_lun
, &new_inquiry_data
);
227 if (res
== B_NAME_IN_USE
) {
228 SHOW_FLOW0(3, "name in use");
229 if (scsi_force_get_device(bus
, target_id
, target_lun
, &device
) != B_OK
)
231 // the device was already registered, let's tell our child to rescan it
232 device_node
*childNode
= NULL
;
233 const device_attr attrs
[] = { { NULL
} };
234 if (pnp
->get_next_child_node(bus
->node
, attrs
, &childNode
) == B_OK
) {
235 pnp
->rescan_node(childNode
);
236 pnp
->put_node(childNode
);
238 scsi_put_forced_device(device
);
243 scsi_free_ccb(worker_req
);
245 scsi_put_forced_device(device
);
252 scsi_scan_bus(scsi_bus_info
*bus
)
254 scsi_path_inquiry inquiry
;
258 // get ID of initiator (i.e. controller)
259 uchar res
= scsi_inquiry_path(bus
, &inquiry
);
260 if (res
!= SCSI_REQ_CMP
)
263 uint initiator_id
= inquiry
.initiator_id
;
265 SHOW_FLOW(3, "initiator_id=%d", initiator_id
);
267 // tell SIM to rescan bus (needed at least by IDE translator)
268 // as this function is optional for SIM, we ignore its result
269 bus
->interface
->scan_bus(bus
->sim_cookie
);
271 for (uint target_id
= 0; target_id
< bus
->max_target_count
; ++target_id
) {
272 SHOW_FLOW(3, "target: %d", target_id
);
274 if (target_id
== initiator_id
)
277 // TODO: there are a lot of devices out there that go mad if you probe
278 // anything but LUN 0, so we should probably add a black-list
280 for (uint lun
= 0; lun
< bus
->max_lun_count
; ++lun
) {
281 SHOW_FLOW(3, "lun: %d", lun
);
283 status_t status
= scsi_scan_lun(bus
, target_id
, lun
);
285 // if there is no device at lun 0, there's probably no device at all
286 if (lun
== 0 && status
!= B_OK
)
291 SHOW_FLOW0(3, "done");