2 * Copyright 2004-2011, Haiku, Inc. All rights reserved.
3 * Copyright 2002-2004, Thomas Kurschel. All rights reserved.
5 * Distributed under the terms of the MIT License.
11 This file is more difficult then you might expect as the SCSI system
12 uses physical addresses everywhere which have to be mapped into
13 virtual address space during transmission. Additionally, during ATAPI
14 commands we may have to transmit more data then exist because the
15 data len specified by the command doesn't need to be the same as
16 of the data buffer provided.
18 The handling of S/G entries of odd size may look superfluous as the
19 SCSI bus manager can take care of that. In general, this would be possible
20 as most controllers need even alignment for DMA as well, but some can
21 handle _any_ S/G list and it wouldn't be sensitive to enforce stricter
22 alignement just for some rare PIO transmissions.
24 Little hint for the meaning of "transferred": this is the number of bytes
25 sent over the bus. For read-transmissions, this may be one more then copied
26 into the buffer (the extra byte read is stored in device->odd_byte), for
27 write-transmissions, this may be one less (the waiting byte is pending in
30 In terms of error handling: we don't bother checking transmission of every
31 single byte via read/write_pio(). At least at the end of the request, when
32 the status bits are verified, we will see that something has gone wrong.
34 TBD: S/G entries may have odd start address. For non-Intel architecture
35 we either have to copy data to an aligned buffer or have to modify
36 PIO-handling in controller drivers.
39 #include "ide_internal.h"
48 // internal error code if scatter gather table is too short
49 #define ERR_TOO_BIG (B_ERRORS_END + 1)
52 /*! Prepare PIO transfer */
54 prep_PIO_transfer(ide_device_info
*device
, ide_qrequest
*qrequest
)
58 device
->left_sg_elem
= qrequest
->request
->sg_count
;
59 device
->cur_sg_elem
= qrequest
->request
->sg_list
;
60 device
->cur_sg_ofs
= 0;
61 device
->has_odd_byte
= false;
62 qrequest
->request
->data_resid
= qrequest
->request
->data_length
;
66 /*! Transfer virtually continuous data */
67 static inline status_t
68 transfer_PIO_virtcont(ide_device_info
*device
, uint8
*virtualAddress
,
69 int length
, bool write
, int *transferred
)
71 ide_bus_info
*bus
= device
->bus
;
72 ide_controller_interface
*controller
= bus
->controller
;
73 void * channel_cookie
= bus
->channel_cookie
;
76 // if there is a byte left from last chunk, transmit it together
77 // with the first byte of the current chunk (IDE requires 16 bits
78 // to be transmitted at once)
79 if (device
->has_odd_byte
) {
82 buffer
[0] = device
->odd_byte
;
83 buffer
[1] = *virtualAddress
++;
85 controller
->write_pio(channel_cookie
, (uint16
*)buffer
, 1, false);
91 controller
->write_pio(channel_cookie
, (uint16
*)virtualAddress
,
94 // take care if chunk size was odd, which means that 1 byte remains
95 virtualAddress
+= length
& ~1;
96 *transferred
+= length
& ~1;
98 device
->has_odd_byte
= (length
& 1) != 0;
100 if (device
->has_odd_byte
)
101 device
->odd_byte
= *virtualAddress
;
103 // if we read one byte too much last time, push it into current chunk
104 if (device
->has_odd_byte
) {
105 *virtualAddress
++ = device
->odd_byte
;
109 SHOW_FLOW(4, "Reading PIO to %p, %d bytes", virtualAddress
, length
);
111 controller
->read_pio(channel_cookie
, (uint16
*)virtualAddress
,
114 // take care of odd chunk size;
115 // in this case we read 1 byte to few!
116 virtualAddress
+= length
& ~1;
117 *transferred
+= length
& ~1;
119 device
->has_odd_byte
= (length
& 1) != 0;
121 if (device
->has_odd_byte
) {
124 // now read the missing byte; as we have to read 2 bytes at once,
125 // we'll read one byte too much
126 controller
->read_pio(channel_cookie
, (uint16
*)buffer
, 1, false);
128 *virtualAddress
= buffer
[0];
129 device
->odd_byte
= buffer
[1];
139 /*! Transmit physically continuous data */
140 static inline status_t
141 transfer_PIO_physcont(ide_device_info
*device
, addr_t physicalAddress
,
142 int length
, bool write
, int *transferred
)
144 // we must split up chunk into B_PAGE_SIZE blocks as we can map only
145 // one page into address space at once
147 addr_t virtualAddress
;
149 int page_left
, cur_len
;
151 Thread
* thread
= thread_get_current_thread();
153 SHOW_FLOW(4, "Transmitting to/from physical address %lx, %d bytes left",
154 physicalAddress
, length
);
156 thread_pin_to_current_cpu(thread
);
157 if (vm_get_physical_page_current_cpu(physicalAddress
, &virtualAddress
,
159 thread_unpin_from_current_cpu(thread
);
160 // ouch: this should never ever happen
161 set_sense(device
, SCSIS_KEY_HARDWARE_ERROR
, SCSIS_ASC_INTERNAL_FAILURE
);
165 // if chunks starts in the middle of a page, we have even less then
167 page_left
= B_PAGE_SIZE
- physicalAddress
% B_PAGE_SIZE
;
169 SHOW_FLOW(4, "page_left=%d", page_left
);
171 cur_len
= min_c(page_left
, length
);
173 SHOW_FLOW(4, "cur_len=%d", cur_len
);
175 err
= transfer_PIO_virtcont(device
, (uint8
*)virtualAddress
,
176 cur_len
, write
, transferred
);
178 vm_put_physical_page_current_cpu(virtualAddress
, handle
);
179 thread_unpin_from_current_cpu(thread
);
185 physicalAddress
+= cur_len
;
192 /*! Transfer PIO block from/to buffer */
194 transfer_PIO_block(ide_device_info
*device
, int length
, bool write
, int *transferred
)
196 // data is usually split up into multiple scatter/gather blocks
198 int left_bytes
, cur_len
;
201 if (device
->left_sg_elem
== 0)
202 // ups - buffer too small (for ATAPI data, this is OK)
205 // we might have transmitted part of a scatter/entry already!
206 left_bytes
= device
->cur_sg_elem
->size
- device
->cur_sg_ofs
;
208 cur_len
= min_c(left_bytes
, length
);
210 err
= transfer_PIO_physcont(device
,
211 (addr_t
)device
->cur_sg_elem
->address
+ device
->cur_sg_ofs
,
212 cur_len
, write
, transferred
);
217 if (left_bytes
<= length
) {
218 // end of one scatter/gather block reached
219 device
->cur_sg_ofs
= 0;
220 ++device
->cur_sg_elem
;
221 --device
->left_sg_elem
;
223 // still in the same block
224 device
->cur_sg_ofs
+= cur_len
;
234 /*! Write zero data (required for ATAPI if we ran out of data) */
237 write_discard_PIO(ide_device_info
*device
, int length
)
239 ide_bus_info
*bus
= device
->bus
;
242 memset(buffer
, 0, sizeof(buffer
));
244 // we transmit 32 zero-bytes at once
245 // (not very efficient but easy to implement - you get what you deserve
246 // when you don't provide enough buffer)
250 // if device asks for odd number of bytes, append an extra byte to
251 // make length even (this is the "length + 1" term)
252 cur_len
= min_c(length
+ 1, (int)(sizeof(buffer
))) / 2;
254 bus
->controller
->write_pio(bus
->channel_cookie
, (uint16
*)buffer
, cur_len
, false);
256 length
-= cur_len
* 2;
261 /*! Read PIO data and discard it (required for ATAPI if buffer was too small) */
263 read_discard_PIO(ide_device_info
*device
, int length
)
265 ide_bus_info
*bus
= device
->bus
;
268 // discard 32 bytes at once (see write_discard_PIO)
272 // read extra byte if length is odd (that's the "length + 1")
273 cur_len
= min_c(length
+ 1, (int)sizeof(buffer
)) / 2;
275 bus
->controller
->read_pio(bus
->channel_cookie
, (uint16
*)buffer
, cur_len
, false);
277 length
-= cur_len
* 2;
283 return: there are 3 possible results
284 NO_ERROR - everything's nice and groovy
285 ERR_TOO_BIG - data buffer was too short, remaining data got discarded
286 B_ERROR - something serious went wrong, sense data was set
289 write_PIO_block(ide_qrequest
*qrequest
, int length
)
291 ide_device_info
*device
= qrequest
->device
;
296 err
= transfer_PIO_block(device
, length
, true, &transferred
);
298 qrequest
->request
->data_resid
-= transferred
;
300 if (err
!= ERR_TOO_BIG
)
303 // there may be a pending odd byte - transmit that now
304 if (qrequest
->device
->has_odd_byte
) {
307 buffer
[0] = device
->odd_byte
;
310 device
->has_odd_byte
= false;
312 qrequest
->request
->data_resid
-= 1;
315 device
->bus
->controller
->write_pio(device
->bus
->channel_cookie
, (uint16
*)buffer
, 1, false);
318 // "transferred" may actually be larger then length because the last odd-byte
319 // is sent together with an extra zero-byte
320 if (transferred
>= length
)
323 // Ouch! the device asks for data but we haven't got any left.
324 // Sadly, this behaviour is OK for ATAPI packets, but there is no
325 // way to tell the device that we don't have any data left;
326 // only solution is to send zero bytes, though it's BAD BAD BAD
327 write_discard_PIO(qrequest
->device
, length
- transferred
);
333 return: see write_PIO_block
336 read_PIO_block(ide_qrequest
*qrequest
, int length
)
338 ide_device_info
*device
= qrequest
->device
;
343 err
= transfer_PIO_block(qrequest
->device
, length
, false, &transferred
);
345 qrequest
->request
->data_resid
-= transferred
;
347 // if length was odd, there's an extra byte waiting in device->odd_byte
348 if (device
->has_odd_byte
) {
350 device
->has_odd_byte
= false;
351 // adjust res_id as the extra byte didn't reach the buffer
352 ++qrequest
->request
->data_resid
;
355 if (err
!= ERR_TOO_BIG
)
358 // the device returns more data then the buffer can store;
359 // for ATAPI this is OK - we just discard remaining bytes (there
360 // is no way to tell ATAPI about that, but we "only" waste time)
362 // perhaps discarding the extra odd-byte was sufficient
363 if (transferred
>= length
)
366 SHOW_FLOW(3, "discarding after %d bytes", transferred
);
367 read_discard_PIO(qrequest
->device
, length
- transferred
);