1 /**
2 *
3 * TODO: description
4 *
5 * This file is a part of USB SCSI CAM for Haiku.
6 * May be used under terms of the MIT License
7 *
8 * Author(s):
9 * Siarzhuk Zharski <imker@gmx.li>
10 *
11 *
12 */
13 #include <string.h>
14
15 #include "usb_scsi.h"
16
17 #include "device_info.h"
18 #include "proto_common.h"
19 #include "tracing.h"
20 #include "usb_defs.h"
21 #include "scsi_commands.h"
22
23 /**
24 \fn:bulk_callback
25 \param cookie:???
26 \param status:???
27 \param data:???
28 \param actual_len:???
29 \return:???
30
31 ???
32 */
bulk_callback(void * cookie,status_t status,void * data,uint32 actual_len)33 void bulk_callback(void *cookie, status_t status, void* data, uint32 actual_len)
34 {
35 TRACE_BULK_CALLBACK(status, actual_len);
36 if(cookie){
37 usb_device_info *udi = (usb_device_info *)cookie;
38 udi->status = status;
39 udi->data = data;
40 udi->actual_len = actual_len;
41 if(udi->status != B_CANCELED)
42 release_sem(udi->trans_sem);
43 }
44 }
45
46 /**
47 \fn:exec_io
48 \param udi: ???
49 \return:???
50
51 ???
52 */
process_data_io(usb_device_info * udi,iovec * sg_data,int32 sg_count,EDirection dir)53 status_t process_data_io(usb_device_info *udi, //sg_buffer *sgb,
54 iovec *sg_data, int32 sg_count, EDirection dir)
55 {
56 status_t status = B_OK;
57 usb_pipe pipe = (dir == eDirIn) ? udi->pipe_in : udi->pipe_out;
58 // TRACE_DATA_IO_SG(data_sg, sglist_count);
59 status = (*udi->usb_m->queue_bulk_v)(pipe, sg_data, sg_count, bulk_callback, udi);
60 if(status == B_OK){
61 status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/);
62 if(status == B_OK){
63 status = udi->status;
64 if(udi->status == B_DEV_STALLED){
65 status_t st=(*udi->usb_m->clear_feature)(pipe, USB_FEATURE_ENDPOINT_HALT);
66 TRACE_ALWAYS("clear_on_STALL:%08x\n",st);
67 }
68 }else{
69 TRACE_ALWAYS("process_data_io:acquire_sem failed:%08x\n", status);
70 (*udi->usb_m->cancel_queued_transfers)(pipe);
71 }
72 } else {
73 TRACE_ALWAYS("process_data_io:queue_bulk_v failed:%08x\n", status);
74 }
75 TRACE_DATA_IO("process_data_io:processed:%d;status:%08x\n", udi->actual_len, status);
76 return status;
77 }
78
transfer_callback(struct _usb_device_info * udi,CCB_SCSIIO * ccbio,int32 residue,status_t status)79 void transfer_callback(struct _usb_device_info *udi, CCB_SCSIIO *ccbio,
80 int32 residue, status_t status)
81 {
82 ccbio->cam_resid = residue;
83 switch(status){
84 case B_OK:
85 ccbio->cam_ch.cam_status = CAM_REQ_CMP;
86 break;
87 case B_CMD_FAILED:
88 case B_CMD_UNKNOWN:{
89 size_t sense_data_len = (0 != ccbio->cam_sense_len) ?
90 ccbio->cam_sense_len : SSD_MIN_SIZE;
91 uchar *sense_data_ptr = (NULL != ccbio->cam_sense_ptr) ?
92 ccbio->cam_sense_ptr : (uchar*)&udi->autosense_data;
93 uint8 lun = ((ccbio->cam_ch.cam_target_lun) << CMD_LUN_SHIFT) & CMD_LUN;
94 scsi_cmd_generic_6 cmd = { REQUEST_SENSE, {lun, 0}, sense_data_len, 0};
95 /* transform command as required by protocol */
96 uint8 *rcmd = udi->scsi_command_buf;
97 uint8 rcmdlen = sizeof(udi->scsi_command_buf);
98 iovec sense_sg = { sense_data_ptr, sense_data_len };
99 TRACE("transfer_callback:requesting sense information "
100 "due status:%08x\n", status);
101 memset(&udi->autosense_data, 0, SSD_FULL_SIZE); /* just to be sure */
102 if(B_OK != (*udi->transform_m->transform)(udi, (uint8 *)&cmd, sizeof(cmd), &rcmd, &rcmdlen)){
103 TRACE_ALWAYS("transfer_callback: REQUEST SENSE command transform failed\n");
104 ccbio->cam_ch.cam_status = CAM_IDE; //?????????
105 break;
106 }
107 /* transfer command to device. SCSI status will be handled in callback */
108 (*udi->protocol_m->transfer)(udi, rcmd, rcmdlen, &sense_sg, 1, sense_data_len,
109 eDirIn, ccbio, sense_callback);
110 }
111 break;
112 case B_CMD_WIRE_FAILED:
113 ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR;
114 break;
115 default:
116 TRACE_ALWAYS("transfer_callback:unknown status:%08x\n", status);
117 ccbio->cam_ch.cam_status = CAM_IDE;
118 break;
119 }
120 }
121
sense_callback(struct _usb_device_info * udi,CCB_SCSIIO * ccbio,int32 residue,status_t status)122 void sense_callback(struct _usb_device_info *udi, CCB_SCSIIO *ccbio,
123 int32 residue, status_t status)
124 {
125 ccbio->cam_sense_resid = residue;
126 switch(status){
127 case B_CMD_UNKNOWN:
128 case B_CMD_FAILED:
129 case B_OK:{
130 bool b_own_data = (ccbio->cam_sense_ptr == NULL);
131 scsi_sense_data *sense_data = b_own_data ?
132 &udi->autosense_data : (scsi_sense_data *)ccbio->cam_sense_ptr;
133 int data_len = (ccbio->cam_sense_len != 0) ? ccbio->cam_sense_len : SSD_MIN_SIZE;
134 TRACE_SENSE_DATA((uint8*)sense_data, data_len);
135 if((sense_data->flags & SSD_KEY) == SSD_KEY_NO_SENSE){
136 /* no problems. normal case for CB handling */
137 TRACE("sense_callback: key OK\n");
138 ccbio->cam_ch.cam_status = CAM_REQ_CMP;
139 } else {
140 if(!b_own_data){ /* we have used CCBIO provided buffer for sense data */
141 TRACE("sense_callback:sense info OK????:%08x \n", sense_data);
142 ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR | CAM_AUTOSNS_VALID;
143 ccbio->cam_scsi_status = SCSI_STATUS_CHECK_CONDITION;
144 } else {
145 /*TODO: ?????????????????????????????????????? */
146 ccbio->cam_ch.cam_status = CAM_REQ_CMP;
147 // ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR /*| CAM_AUTOSNS_VALID*/;
148 // ccbio->cam_scsi_status = SCSI_STATUS_CHECK_CONDITION;
149 TRACE("sense_callback: sense still not handled...\n");
150 }
151 }
152 }
153 break;
154 default:
155 TRACE_ALWAYS("sense_callback:unknown status:%08x\n", status);
156 case B_CMD_WIRE_FAILED:
157 ccbio->cam_ch.cam_status = CAM_AUTOSENSE_FAIL;
158 break;
159 }
160 }
161
162