5757
5858#define MMC_BLOCK_SIZE 512
5959
60+ /*
61+ * Number of retry attempts when an RPMB authenticated write triggers a UNIT
62+ * ATTENTION
63+ */
64+ #define UFS_RPMB_WRITE_RETRY_COUNT 1
65+ /*
66+ * Number of retry attempts when an RPMB read operation triggers a UNIT
67+ * ATTENTION
68+ */
69+ #define UFS_RPMB_READ_RETRY_COUNT 3
70+
6071/*
6172 * There should be no timeout for security protocol ioctl call, so we choose a
6273 * large number for timeout.
@@ -180,14 +191,20 @@ static void set_sg_io_hdr(sg_io_hdr_t* io_hdrp, int dxfer_direction, unsigned ch
180191}
181192
182193/**
183- * unexpected_scsi_sense - Check for unexpected codes in the sense buffer.
184- * @sense_buf: buffer containing sense data
185- * @len: length of @sense_buf
194+ * enum scsi_result - Results of checking the SCSI status and sense buffer
186195 *
187- * Return: %true if the sense data is not valid or contains an unexpected sense
188- * code, %false otherwise.
196+ * @SCSI_RES_OK: SCSI status and sense are good
197+ * @SCSI_RES_ERR: SCSI status or sense contain an unhandled error
198+ * @SCSI_RES_RETRY: SCSI sense buffer contains a status that indicates that the
199+ * command should be retried
189200 */
190- static bool unexpected_scsi_sense (const uint8_t * sense_buf , size_t len ) {
201+ enum scsi_result {
202+ SCSI_RES_OK = 0 ,
203+ SCSI_RES_ERR ,
204+ SCSI_RES_RETRY ,
205+ };
206+
207+ static enum scsi_result check_scsi_sense (const uint8_t * sense_buf , size_t len ) {
191208 uint8_t response_code = 0 ;
192209 uint8_t sense_key = 0 ;
193210 uint8_t additional_sense_code = 0 ;
@@ -196,14 +213,14 @@ static bool unexpected_scsi_sense(const uint8_t* sense_buf, size_t len) {
196213
197214 if (!sense_buf || len == 0 ) {
198215 ALOGE ("Invalid SCSI sense buffer, length: %zu\n" , len );
199- return true ;
216+ return SCSI_RES_ERR ;
200217 }
201218
202219 response_code = 0x7f & sense_buf [0 ];
203220
204221 if (response_code < 0x70 || response_code > 0x73 ) {
205222 ALOGE ("Invalid SCSI sense response code: %hhu\n" , response_code );
206- return true ;
223+ return SCSI_RES_ERR ;
207224 }
208225
209226 if (response_code >= 0x72 ) {
@@ -241,31 +258,43 @@ static bool unexpected_scsi_sense(const uint8_t* sense_buf, size_t len) {
241258 case 0x0f : /* COMPLETED, not present in kernel headers */
242259 ALOGD ("SCSI success with sense data: key=%hhu, asc=%hhu, ascq=%hhu\n" , sense_key ,
243260 additional_sense_code , additional_sense_code_qualifier );
244- return false;
261+ return SCSI_RES_OK ;
262+ case UNIT_ATTENTION :
263+ ALOGD ("UNIT ATTENTION with sense data: key=%hhu, asc=%hhu, ascq=%hhu\n" , sense_key ,
264+ additional_sense_code , additional_sense_code_qualifier );
265+ if (additional_sense_code == 0x29 ) {
266+ /* POWER ON or RESET condition */
267+ return SCSI_RES_RETRY ;
268+ }
269+
270+ /* treat this UNIT ATTENTION as an error if we don't recognize it */
271+ break ;
245272 }
246273
247274 ALOGE ("Unexpected SCSI sense data: key=%hhu, asc=%hhu, ascq=%hhu\n" , sense_key ,
248275 additional_sense_code , additional_sense_code_qualifier );
249276 log_buf (ANDROID_LOG_ERROR , "sense buffer: " , sense_buf , len );
250- return true ;
277+ return SCSI_RES_ERR ;
251278}
252279
253- static void check_sg_io_hdr (const sg_io_hdr_t * io_hdrp ) {
280+ static enum scsi_result check_sg_io_hdr (const sg_io_hdr_t * io_hdrp ) {
254281 if (io_hdrp -> status == 0 && io_hdrp -> host_status == 0 && io_hdrp -> driver_status == 0 ) {
255- return ;
282+ return SCSI_RES_OK ;
256283 }
257284
258285 if (io_hdrp -> status & 0x01 ) {
259286 ALOGE ("SG_IO received unknown status, LSB is set: %hhu" , io_hdrp -> status );
260287 }
261288
262289 if (io_hdrp -> masked_status != GOOD && io_hdrp -> sb_len_wr > 0 ) {
263- bool sense_error = unexpected_scsi_sense (io_hdrp -> sbp , io_hdrp -> sb_len_wr );
264- if (sense_error ) {
290+ enum scsi_result scsi_res = check_scsi_sense (io_hdrp -> sbp , io_hdrp -> sb_len_wr );
291+ if (scsi_res == SCSI_RES_RETRY ) {
292+ return SCSI_RES_RETRY ;
293+ } else if (scsi_res != SCSI_RES_OK ) {
265294 ALOGE ("Unexpected SCSI sense. masked_status: %hhu, host_status: %hu, driver_status: "
266295 "%hu\n" ,
267296 io_hdrp -> masked_status , io_hdrp -> host_status , io_hdrp -> driver_status );
268- return ;
297+ return scsi_res ;
269298 }
270299 }
271300
@@ -278,7 +307,7 @@ static void check_sg_io_hdr(const sg_io_hdr_t* io_hdrp) {
278307 default :
279308 ALOGE ("SG_IO failed with masked_status: %hhu, host_status: %hu, driver_status: %hu\n" ,
280309 io_hdrp -> masked_status , io_hdrp -> host_status , io_hdrp -> driver_status );
281- return ;
310+ return SCSI_RES_ERR ;
282311 }
283312
284313 if (io_hdrp -> host_status != 0 ) {
@@ -289,6 +318,7 @@ static void check_sg_io_hdr(const sg_io_hdr_t* io_hdrp) {
289318 if (io_hdrp -> resid != 0 ) {
290319 ALOGE ("SG_IO resid was non-zero: %d\n" , io_hdrp -> resid );
291320 }
321+ return SCSI_RES_ERR ;
292322}
293323
294324static int send_mmc_rpmb_req (int mmc_fd , const struct storage_rpmb_send_req * req ) {
@@ -363,6 +393,8 @@ static int send_ufs_rpmb_req(int sg_fd, const struct storage_rpmb_send_req* req)
363393 struct sec_proto_cdb out_cdb = {0xB5 , 0xEC , 0x00 , 0x01 , 0x00 , 0x00 , 0 , 0x00 , 0x00 };
364394 unsigned char sense_buffer [32 ];
365395
396+ bool is_request_write = req -> reliable_write_size > 0 ;
397+
366398 wl_rc = acquire_wake_lock (PARTIAL_WAKE_LOCK , UFS_WAKE_LOCK_NAME );
367399 if (wl_rc < 0 ) {
368400 ALOGE ("%s: failed to acquire wakelock: %d, %s\n" , __func__ , wl_rc , strerror (errno ));
@@ -371,32 +403,44 @@ static int send_ufs_rpmb_req(int sg_fd, const struct storage_rpmb_send_req* req)
371403
372404 if (req -> reliable_write_size ) {
373405 /* Prepare SECURITY PROTOCOL OUT command. */
374- out_cdb .length = __builtin_bswap32 (req -> reliable_write_size );
375406 sg_io_hdr_t io_hdr ;
376- set_sg_io_hdr (& io_hdr , SG_DXFER_TO_DEV , sizeof (out_cdb ), sizeof (sense_buffer ),
377- req -> reliable_write_size , (void * )write_buf , (unsigned char * )& out_cdb ,
378- sense_buffer );
379- rc = ioctl (sg_fd , SG_IO , & io_hdr );
380- if (rc < 0 ) {
381- ALOGE ("%s: ufs ioctl failed: %d, %s\n" , __func__ , rc , strerror (errno ));
382- goto err_op ;
383- }
384- check_sg_io_hdr (& io_hdr );
407+ int retry_count = UFS_RPMB_WRITE_RETRY_COUNT ;
408+ do {
409+ out_cdb .length = __builtin_bswap32 (req -> reliable_write_size );
410+ set_sg_io_hdr (& io_hdr , SG_DXFER_TO_DEV , sizeof (out_cdb ), sizeof (sense_buffer ),
411+ req -> reliable_write_size , (void * )write_buf , (unsigned char * )& out_cdb ,
412+ sense_buffer );
413+ rc = ioctl (sg_fd , SG_IO , & io_hdr );
414+ if (rc < 0 ) {
415+ ALOGE ("%s: ufs ioctl failed: %d, %s\n" , __func__ , rc , strerror (errno ));
416+ goto err_op ;
417+ }
418+ } while (check_sg_io_hdr (& io_hdr ) == SCSI_RES_RETRY && retry_count -- > 0 );
385419 write_buf += req -> reliable_write_size ;
386420 }
387421
388422 if (req -> write_size ) {
389423 /* Prepare SECURITY PROTOCOL OUT command. */
390- out_cdb .length = __builtin_bswap32 (req -> write_size );
391424 sg_io_hdr_t io_hdr ;
392- set_sg_io_hdr (& io_hdr , SG_DXFER_TO_DEV , sizeof (out_cdb ), sizeof (sense_buffer ),
393- req -> write_size , (void * )write_buf , (unsigned char * )& out_cdb , sense_buffer );
394- rc = ioctl (sg_fd , SG_IO , & io_hdr );
395- if (rc < 0 ) {
396- ALOGE ("%s: ufs ioctl failed: %d, %s\n" , __func__ , rc , strerror (errno ));
397- goto err_op ;
398- }
399- check_sg_io_hdr (& io_hdr );
425+ /*
426+ * We don't retry write response request messages (is_request_write ==
427+ * true) because a unit attention condition between the write and
428+ * requesting a response means that the device was reset and we can't
429+ * get a response to our original write. We can only retry this SG_IO
430+ * call when it is the first call in our sequence.
431+ */
432+ int retry_count = is_request_write ? 0 : UFS_RPMB_READ_RETRY_COUNT ;
433+ do {
434+ out_cdb .length = __builtin_bswap32 (req -> write_size );
435+ set_sg_io_hdr (& io_hdr , SG_DXFER_TO_DEV , sizeof (out_cdb ), sizeof (sense_buffer ),
436+ req -> write_size , (void * )write_buf , (unsigned char * )& out_cdb ,
437+ sense_buffer );
438+ rc = ioctl (sg_fd , SG_IO , & io_hdr );
439+ if (rc < 0 ) {
440+ ALOGE ("%s: ufs ioctl failed: %d, %s\n" , __func__ , rc , strerror (errno ));
441+ goto err_op ;
442+ }
443+ } while (check_sg_io_hdr (& io_hdr ) == SCSI_RES_RETRY && retry_count -- > 0 );
400444 write_buf += req -> write_size ;
401445 }
402446
0 commit comments