1 /*
2 ********************************************************************************************************************
3 *                                              usb host driver
4 *
5 *                              (c) Copyright 2007-2010, javen.China
6 *                                       All Rights Reserved
7 *
8 * File Name     : mscTransport_i.c
9 *
10 * Author        : javen
11 *
12 * Version       : 2.0
13 *
14 * Date          : 2010.7.12
15 *
16 * Description   :
17 *     USB Mass Storage Class传输容错辅助处理部分。
18 *
19 *     这部分主要是为了解决USB光驱中光盘突然弹出时,USB容错时间过长。其原因是Lun中media已经不存在,但是lun本身还在,
20 * 虽不可读/写数据,但是可以操作Lun。因此现在增加了在读写操作超时后,先去test_unit_ready,判断Lun的状态后,
21 * 再决定下一步的操作。
22 *
23 * History       :
24 *
25 ********************************************************************************************************************
26 */
27 #include  "usb_os_platform.h"
28 #include  "error.h"
29 #include  "usb_host_common.h"
30 #include  "urb.h"
31 #include  "usb_gen_hub.h"
32 #include  "usb_msc_i.h"
33 #include  "mscTransport.h"
34 #include  "Scsi2.h"
35 
36 /*
37 *******************************************************************************
38 *                     mscTransportRequestSense
39 *
40 * Description:
41 *
42 *
43 * Parameters:
44 *
45 *
46 * Return value:
47 *
48 *
49 * note:
50 *
51 *
52 *******************************************************************************
53 */
mscTransportRequestSense(__mscLun_t * mscLun,void * buffer,unsigned int buffer_len)54 static int mscTransportRequestSense(__mscLun_t *mscLun, void *buffer, unsigned int buffer_len)
55 {
56     __ScsiCmnd_t ScsiCmnd;
57     unsigned char CB[MAX_CDB];
58     unsigned int ret = 0;
59 
60     if (mscLun == NULL || buffer == NULL)
61     {
62 //        printf("ERR: ScsiInquery: input error, mscLun = %x, buffer = %x\n", (unsigned int)mscLun, (unsigned int)buffer);
63         return USB_STATUS_BAD_ARGUMENTS;
64     }
65 
66     if (buffer_len == 0)
67     {
68         printf("ERR: ScsiInquery: input error, buffer_len == %d\n", buffer_len);
69         return USB_STATUS_BUFFER_TOO_SMALL;
70     }
71 
72     memset((void *)&ScsiCmnd, 0, sizeof(__ScsiCmnd_t));
73     memset(CB, 0, MAX_CDB);
74     /* create command block */
75     CB[0] = SCSI_REQUEST_SENSE;             /* scsi command         */
76     CB[1] = ((mscLun->LunNo & 0x7) << 5);   /* lun                  */
77     CB[4] = buffer_len;                     /* Allocation Length    */
78     /* initialize transport command */
79     ScsiCmnd.cmnd.data_direction    = DATA_FROM_DEVICE;
80     ScsiCmnd.cmnd.Timeout       = SCSI_COMMAND_TIMEOUT;
81     ScsiCmnd.cmnd.dwLun         = mscLun->LunNo;
82     ScsiCmnd.cmnd.CBLen         = (USBMSC_SUBCLASS_SCSI == mscLun->DiskSubClass) ? SCSI_CDB_6 : UFI_CDB;
83     ScsiCmnd.cmnd.CommandBlock  = CB;
84     /* initialize scsi_cnmd */
85     ScsiCmnd.sc_lun             = mscLun;
86     ScsiCmnd.allowed            = SCSI_CMD_RETRY;
87     ScsiCmnd.DataTransferLength = buffer_len;
88     ScsiCmnd.buffer             = buffer;
89     ret = mscBoTransport(mscLun->mscDev, &ScsiCmnd);
90     return ret;
91 }
92 
93 /*
94 *******************************************************************************
95 *                     mscTransportGetSenseData
96 *
97 * Description:
98 *
99 *
100 * Parameters:
101 *
102 *
103 * Return value:
104 *
105 *
106 * note:
107 *
108 *
109 *******************************************************************************
110 */
mscTransportGetSenseData(__mscLun_t * mscLun)111 static int mscTransportGetSenseData(__mscLun_t *mscLun)
112 {
113     __SenseData_t SenseData;
114     int ret = 0;
115     memset(&SenseData, 0, sizeof(__SenseData_t));
116     ret = mscTransportRequestSense(mscLun, (void *)&SenseData, sizeof(__SenseData_t));
117 
118     if (ret != USB_STOR_TRANSPORT_GOOD)
119     {
120         printf("ERR: mscTransportGetSenseData failed\n");
121         return USB_ERR_BAD_ARGUMENTS;
122     }
123 
124     printf("mscReason:SenseKey = %x, AdditionalSenseCode = %x\n",
125                SenseData.SenseKey, SenseData.AdditionalSenseCode);
126 
127     switch (SenseData.SenseKey)
128     {
129         case SENSE_NONE :
130             ret = USB_ERR_SUCCESS;
131             break;
132 
133         case SENSE_NOT_READY :
134             switch (SenseData.AdditionalSenseCode)
135             {
136                 case ASC_MEDIUM_NOT_PRESENT :
137                     printf("ERR: media is not present\n");
138                     mscLun->MediaPresent = 0;
139                     ret = USB_ERR_MEDIA_NOT_PRESENT;
140                     break;
141 
142                 default:
143                     printf("ERR: unkown ASC(%d)\n", SenseData.AdditionalSenseCode);
144                     ret = USB_ERR_UNKOWN_ERROR;
145                     break;
146             }
147 
148             break;
149 
150         case SENSE_ILLEGAL_REQUEST :
151             ret = USB_ERR_NOT_SUPPORT_COMMAND;
152             break;
153 
154         case SENSE_UNIT_ATTENTION :
155             switch (SenseData.AdditionalSenseCode)
156             {
157                 case ASC_MEDIUM_NOT_PRESENT :
158                     printf("ERR: media is not present\n");
159                     mscLun->MediaPresent = 0;
160                     ret = USB_ERR_MEDIA_NOT_PRESENT;
161                     break;
162 
163                 default:
164                     printf("ERR: unkown ASC(%d)\n", SenseData.AdditionalSenseCode);
165                     ret = USB_ERR_UNKOWN_ERROR;
166             }
167 
168             break;
169 
170         default:
171             ret = USB_ERR_UNKOWN_ERROR;
172     }
173 
174     return ret;
175 }
176 
177 /*
178 *******************************************************************************
179 *                     mscGetDataTransportReason
180 *
181 * Description:
182 *
183 *
184 * Parameters:
185 *
186 *
187 * Return value:
188 *
189 *
190 * note:
191 *
192 *
193 *******************************************************************************
194 */
mscGetDataTransportReason(__mscLun_t * mscLun,__ScsiCmnd_t * ScsiCmnd)195 int mscGetDataTransportReason(__mscLun_t *mscLun, __ScsiCmnd_t *ScsiCmnd)
196 {
197     int ret = USB_ERR_COMMAND_NEED_RETRY;
198     unsigned char  Command = 0;
199     int status = 0;
200 
201     if (mscLun == NULL || ScsiCmnd == NULL)
202     {
203         printf("ERR: input error\n");
204         return USB_ERR_COMMAND_NEED_RETRY;
205     }
206 
207     status = mscTransportGetSenseData(mscLun);
208 
209     if (status == USB_ERR_MEDIA_NOT_PRESENT || status == USB_ERR_NOT_SUPPORT_COMMAND)
210     {
211         Command = ((unsigned char *)(ScsiCmnd->cmnd.CommandBlock))[0];
212 
213         if (Command == SCSI_READ6 || Command == SCSI_READ10 || Command == SCSI_READ16
214             || Command == SCSI_WRITE6 || Command == SCSI_WRITE10 || Command == SCSI_WRITE16)
215         {
216             printf("ERR: Command(%x) execute failed, for media is not present\n", Command);
217             ret = USB_ERR_COMMAND_EXECUTE_FAILED;
218         }
219     }
220 
221     return ret;
222 }
223 
224