2 * Copyright 2013, Jérôme Duval, korli@users.berlios.de.
3 * Copyright 2009, Michael Lotz, mmlr@mlotz.ch.
4 * Distributed under the terms of the MIT License.
8 #include "VirtioSCSIPrivate.h"
13 VirtioSCSIRequest::VirtioSCSIRequest(bool hasLock
)
16 fStatus(SCSI_REQ_CMP
),
23 mutex_init(&fLock
, "virtio scsi request");
25 fBuffer
= malloc(sizeof(struct virtio_scsi_cmd_req
)
26 + sizeof(struct virtio_scsi_cmd_resp
));
27 bzero(fBuffer
, sizeof(struct virtio_scsi_cmd_req
)
28 + sizeof(struct virtio_scsi_cmd_resp
));
30 fRequest
= (struct virtio_scsi_cmd_req
*)fBuffer
;
31 fResponse
= (struct virtio_scsi_cmd_resp
*)
32 ((addr_t
)fBuffer
+ sizeof(struct virtio_scsi_cmd_req
));
34 fResponse
->sense_len
= 0;
38 VirtioSCSIRequest::~VirtioSCSIRequest()
41 mutex_destroy(&fLock
);
48 VirtioSCSIRequest::SetStatus(uint8 status
)
55 VirtioSCSIRequest::SetTimeout(bigtime_t timeout
)
62 VirtioSCSIRequest::SetIsWrite(bool isWrite
)
69 VirtioSCSIRequest::SetBytesLeft(uint32 bytesLeft
)
71 fBytesLeft
= bytesLeft
;
76 VirtioSCSIRequest::Start(scsi_ccb
*ccb
)
79 if (mutex_trylock(&fLock
) != B_OK
)
83 fStatus
= SCSI_REQ_CMP
;
84 fCCB
->device_status
= SCSI_STATUS_GOOD
;
86 bzero(fResponse
, sizeof(struct virtio_scsi_cmd_resp
));
88 TRACE("VirtioSCSIRequest::Start() opcode %x tid %x lun %x\n", ccb
->cdb
[0],
89 ccb
->target_id
, ccb
->target_lun
);
96 VirtioSCSIRequest::Finish(bool resubmit
)
99 fStatus
= _ResponseStatus();
100 fCCB
->data_resid
= fResponse
->resid
;
101 fCCB
->subsys_status
= fStatus
;
103 TRACE("VirtioSCSIRequest::Finish() status 0x%x response 0x%x resid:0x%x"
104 " sense_len:%x\n", fResponse
->status
, fResponse
->response
,
105 fResponse
->resid
, fResponse
->sense_len
);
107 if (fCCB
->cdb
[0] == SCSI_OP_INQUIRY
) {
108 // when the request is an inquiry, don't do anything
109 } else if (fStatus
== SCSI_REQ_CMP
&& fResponse
->status
!= 0
111 // when the request completed and has set sense
112 // data, report this to the scsi stack by setting
113 // CHECK CONDITION status
114 TRACE("setting check condition\n");
116 fCCB
->subsys_status
= SCSI_REQ_CMP_ERR
;
117 fCCB
->device_status
= SCSI_STATUS_CHECK_CONDITION
;
119 // copy sense data if caller requested it
120 if ((fCCB
->flags
& SCSI_DIS_AUTOSENSE
) == 0) {
121 size_t senseLength
= min_c(sizeof(fCCB
->sense
),
122 fResponse
->sense_len
);
123 memcpy(fCCB
->sense
, fResponse
->sense
, senseLength
);
124 fCCB
->sense_resid
= sizeof(fCCB
->sense
) - senseLength
;
125 fCCB
->subsys_status
|= SCSI_AUTOSNS_VALID
;
129 mutex_unlock(&fLock
);
132 gSCSI
->resubmit(fCCB
);
134 gSCSI
->finished(fCCB
, 1);
136 TRACE("VirtioSCSIRequest::Finish() done\n");
143 VirtioSCSIRequest::RequestSense()
146 // Copy sense data from last request into data buffer of current request.
147 // The sense data of last request is still present in the current request,
148 // as it isn't cleared on SCSI_OP_REQUEST_SENSE.
149 scsi_cmd_request_sense
*command
= (scsi_cmd_request_sense
*)fCCB
->cdb
;
150 copy_sg_data(fCCB
, 0, command
->allocation_length
, fResponse
->sense
,
151 fResponse
->sense_len
, false);
153 fCCB
->data_resid
= fCCB
->data_length
- min_c(min_c(fResponse
->sense_len
,
154 command
->allocation_length
), fCCB
->data_length
);
155 fResponse
->sense_len
= 0;
160 VirtioSCSIRequest::FillRequest(uint32 inCount
, uint32 outCount
,
161 physical_entry
*entries
)
164 fRequest
->task_attr
= VIRTIO_SCSI_S_SIMPLE
;
165 fRequest
->tag
= (addr_t
)fCCB
;
166 fRequest
->lun
[0] = 1;
167 fRequest
->lun
[1] = fCCB
->target_id
;
168 // we don't support lun >= 256
169 fRequest
->lun
[2] = 0x40;
170 fRequest
->lun
[3] = fCCB
->target_lun
& 0xff;
172 memcpy(fRequest
->cdb
, fCCB
->cdb
, min_c(fCCB
->cdb_length
,
173 min_c(sizeof(fRequest
->cdb
), sizeof(fCCB
->cdb
))));
175 get_memory_map(fBuffer
, sizeof(struct virtio_scsi_cmd_req
)
176 + sizeof(struct virtio_scsi_cmd_resp
), &entries
[0], 1);
177 entries
[0].size
= sizeof(struct virtio_scsi_cmd_req
);
179 memcpy(entries
+ 1, fCCB
->sg_list
, fCCB
->sg_count
180 * sizeof(physical_entry
));
183 entries
[outCount
].address
= entries
[0].address
184 + sizeof(struct virtio_scsi_cmd_req
);
185 entries
[outCount
].size
= sizeof(struct virtio_scsi_cmd_resp
);
188 memcpy(entries
+ outCount
+ 1, fCCB
->sg_list
, fCCB
->sg_count
189 * sizeof(physical_entry
));
195 VirtioSCSIRequest::_ResponseStatus()
199 switch (fResponse
->response
) {
200 case VIRTIO_SCSI_S_OK
:
201 status
= SCSI_REQ_CMP
;
203 case VIRTIO_SCSI_S_OVERRUN
:
204 status
= SCSI_DATA_RUN_ERR
;
206 case VIRTIO_SCSI_S_ABORTED
:
207 status
= SCSI_REQ_ABORTED
;
209 case VIRTIO_SCSI_S_BAD_TARGET
:
210 status
= SCSI_TID_INVALID
;
212 case VIRTIO_SCSI_S_RESET
:
213 status
= SCSI_SCSI_BUS_RESET
;
215 case VIRTIO_SCSI_S_BUSY
:
216 status
= SCSI_SCSI_BUSY
;
218 case VIRTIO_SCSI_S_TRANSPORT_FAILURE
:
219 case VIRTIO_SCSI_S_TARGET_FAILURE
:
220 case VIRTIO_SCSI_S_NEXUS_FAILURE
:
221 status
= SCSI_NO_NEXUS
;
223 default: /* VIRTIO_SCSI_S_FAILURE */
224 status
= SCSI_REQ_CMP_ERR
;