2 * Copyright 2004-2013, Haiku, Inc. All RightsReserved.
3 * Copyright 2002-2003, Thomas Kurschel. All rights reserved.
5 * Distributed under the terms of the MIT License.
9 //! Handling of block device
14 #include <AutoDeleter.h>
16 #include "scsi_periph_int.h"
20 periph_check_capacity(scsi_periph_device_info
*device
, scsi_ccb
*request
)
22 scsi_res_read_capacity capacityResult
;
23 scsi_cmd_read_capacity
*cmd
= (scsi_cmd_read_capacity
*)request
->cdb
;
28 SHOW_FLOW(3, "%p, %p", device
, request
);
30 // driver doesn't support capacity callback - seems to be no block
31 // device driver, so ignore
32 if (device
->callbacks
->set_capacity
== NULL
)
35 request
->flags
= SCSI_DIR_IN
;
37 request
->data
= (uint8
*)&capacityResult
;
38 request
->data_length
= sizeof(capacityResult
);
39 request
->cdb_length
= sizeof(scsi_cmd_read_capacity
);
40 request
->timeout
= device
->std_timeout
;
42 request
->sg_list
= NULL
;
44 memset(cmd
, 0, sizeof(*cmd
));
45 cmd
->opcode
= SCSI_OP_READ_CAPACITY
;
46 // we don't set PMI (partial medium indicator) as we want the whole capacity;
47 // in this case, all other parameters must be zero
49 res
= periph_safe_exec(device
, request
);
51 if (res
== B_DEV_MEDIA_CHANGED
) {
52 // in this case, the error handler has already called check_capacity
53 // recursively, so we ignore our (invalid) result
54 SHOW_FLOW0( 3, "ignore result because medium change" );
55 return B_DEV_MEDIA_CHANGED
;
58 mutex_lock(&device
->mutex
);
60 if (res
== B_OK
&& request
->data_resid
== 0) {
61 capacity
= B_BENDIAN_TO_HOST_INT32(capacityResult
.lba
);
63 if (capacity
== UINT_MAX
) {
64 mutex_unlock(&device
->mutex
);
66 scsi_cmd_read_capacity_long
*cmd
67 = (scsi_cmd_read_capacity_long
*)request
->cdb
;
69 scsi_res_read_capacity_long capacityLongResult
;
70 request
->data
= (uint8
*)&capacityLongResult
;
71 request
->data_length
= sizeof(capacityLongResult
);
72 request
->cdb_length
= sizeof(scsi_cmd_read_capacity_long
);
74 memset(cmd
, 0, sizeof(*cmd
));
75 cmd
->opcode
= SCSI_OP_SERVICE_ACTION_IN
;
76 cmd
->service_action
= SCSI_SAI_READ_CAPACITY_16
;
78 res
= periph_safe_exec(device
, request
);
80 mutex_lock(&device
->mutex
);
82 if (res
== B_OK
&& request
->data_resid
== 0) {
83 capacity
= B_BENDIAN_TO_HOST_INT64(capacityLongResult
.lba
);
88 // the command returns the index of the _last_ block,
89 // i.e. the size is one larger
92 blockSize
= B_BENDIAN_TO_HOST_INT32(capacityResult
.block_size
);
98 SHOW_FLOW(3, "capacity = %" B_PRId64
", block_size = %" B_PRId32
, capacity
,
101 device
->block_size
= blockSize
;
103 device
->callbacks
->set_capacity(device
->periph_device
,
104 capacity
, blockSize
);
106 /* device->byte2blk_shift = log2( device->block_size );
107 if( device->byte2blk_shift < 0 ) {
108 // this may be too restrictive...
109 device->capacity = -1;
110 return ERR_DEV_GENERAL;
113 mutex_unlock(&device
->mutex
);
115 SHOW_FLOW(3, "done (%s)", strerror(res
));
122 periph_trim_device(scsi_periph_device_info
*device
, scsi_ccb
*request
,
123 scsi_block_range
* ranges
, uint32 rangeCount
)
125 size_t unmapBlockSize
= (rangeCount
- 1)
126 * sizeof(scsi_unmap_block_descriptor
)
127 + sizeof(scsi_unmap_parameter_list
);
129 // TODO: check block limits VPD page
130 // TODO: instead of failing, we should try to complete the request in
132 if (unmapBlockSize
> 65536 || rangeCount
== 0)
135 scsi_unmap_parameter_list
* unmapBlocks
136 = (scsi_unmap_parameter_list
*)malloc(unmapBlockSize
);
137 if (unmapBlocks
== NULL
)
140 MemoryDeleter
deleter(unmapBlocks
);
142 // Prepare request data
143 memset(unmapBlocks
, 0, unmapBlockSize
);
144 unmapBlocks
->data_length
= B_HOST_TO_BENDIAN_INT16(unmapBlockSize
- 1);
145 unmapBlocks
->block_data_length
146 = B_HOST_TO_BENDIAN_INT16(unmapBlockSize
- 7);
148 for (uint32 i
= 0; i
< rangeCount
; i
++) {
149 unmapBlocks
->blocks
[i
].lba
= B_HOST_TO_BENDIAN_INT64(
150 ranges
[i
].offset
/ device
->block_size
);
151 unmapBlocks
->blocks
[i
].block_count
= B_HOST_TO_BENDIAN_INT32(
152 ranges
[i
].size
/ device
->block_size
);
155 request
->flags
= SCSI_DIR_OUT
;
156 request
->sort
= ranges
[0].offset
/ device
->block_size
;
157 request
->timeout
= device
->std_timeout
;
159 scsi_cmd_unmap
* cmd
= (scsi_cmd_unmap
*)request
->cdb
;
161 memset(cmd
, 0, sizeof(*cmd
));
162 cmd
->opcode
= SCSI_OP_UNMAP
;
163 cmd
->length
= B_HOST_TO_BENDIAN_INT16(unmapBlockSize
);
165 request
->data
= (uint8
*)unmapBlocks
;
166 request
->data_length
= unmapBlockSize
;
168 request
->cdb_length
= sizeof(*cmd
);
170 status_t status
= periph_safe_exec(device
, request
);
172 // peripheral layer only creates "read" error
173 if (status
== B_DEV_READ_ERROR
)
174 return B_DEV_WRITE_ERROR
;