@@ -890,7 +890,7 @@ static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
890
890
return 0 ;
891
891
}
892
892
893
- /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
893
+ /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
894
894
static int fill_from_dev_buffer (struct scsi_cmnd * scp , unsigned char * arr ,
895
895
int arr_len )
896
896
{
@@ -909,7 +909,35 @@ static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
909
909
return 0 ;
910
910
}
911
911
912
- /* Returns number of bytes fetched into 'arr' or -1 if error. */
912
+ /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
913
+ * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
914
+ * calls, not required to write in ascending offset order. Assumes resid
915
+ * set to scsi_bufflen() prior to any calls.
916
+ */
917
+ static int p_fill_from_dev_buffer (struct scsi_cmnd * scp , const void * arr ,
918
+ int arr_len , unsigned int off_dst )
919
+ {
920
+ int act_len , n ;
921
+ struct scsi_data_buffer * sdb = scsi_in (scp );
922
+ off_t skip = off_dst ;
923
+
924
+ if (sdb -> length <= off_dst )
925
+ return 0 ;
926
+ if (!(scsi_bidi_cmnd (scp ) || scp -> sc_data_direction == DMA_FROM_DEVICE ))
927
+ return DID_ERROR << 16 ;
928
+
929
+ act_len = sg_pcopy_from_buffer (sdb -> table .sgl , sdb -> table .nents ,
930
+ arr , arr_len , skip );
931
+ pr_debug ("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n" ,
932
+ __func__ , off_dst , scsi_bufflen (scp ), act_len , sdb -> resid );
933
+ n = (int )scsi_bufflen (scp ) - ((int )off_dst + act_len );
934
+ sdb -> resid = min (sdb -> resid , n );
935
+ return 0 ;
936
+ }
937
+
938
+ /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
939
+ * 'arr' or -1 if error.
940
+ */
913
941
static int fetch_to_dev_buffer (struct scsi_cmnd * scp , unsigned char * arr ,
914
942
int arr_len )
915
943
{
@@ -3269,6 +3297,8 @@ static int resp_get_lba_status(struct scsi_cmnd *scp,
3269
3297
return fill_from_dev_buffer (scp , arr , SDEBUG_GET_LBA_STATUS_LEN );
3270
3298
}
3271
3299
3300
+ #define RL_BUCKET_ELEMS 8
3301
+
3272
3302
/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3273
3303
* (W-LUN), the normal Linux scanning logic does not associate it with a
3274
3304
* device (e.g. /dev/sg7). The following magic will make that association:
@@ -3285,12 +3315,14 @@ static int resp_report_luns(struct scsi_cmnd *scp,
3285
3315
unsigned char select_report ;
3286
3316
u64 lun ;
3287
3317
struct scsi_lun * lun_p ;
3288
- u8 * arr ;
3318
+ u8 arr [ RL_BUCKET_ELEMS * sizeof ( struct scsi_lun )] ;
3289
3319
unsigned int lun_cnt ; /* normal LUN count (max: 256) */
3290
3320
unsigned int wlun_cnt ; /* report luns W-LUN count */
3291
3321
unsigned int tlun_cnt ; /* total LUN count */
3292
3322
unsigned int rlen ; /* response length (in bytes) */
3293
- int i , res ;
3323
+ int k , j , n , res ;
3324
+ unsigned int off_rsp = 0 ;
3325
+ const int sz_lun = sizeof (struct scsi_lun );
3294
3326
3295
3327
clear_luns_changed_on_target (devip );
3296
3328
@@ -3329,33 +3361,40 @@ static int resp_report_luns(struct scsi_cmnd *scp,
3329
3361
-- lun_cnt ;
3330
3362
3331
3363
tlun_cnt = lun_cnt + wlun_cnt ;
3332
-
3333
- rlen = (tlun_cnt * sizeof (struct scsi_lun )) + 8 ;
3334
- arr = vmalloc (rlen );
3335
- if (!arr ) {
3336
- mk_sense_buffer (scp , ILLEGAL_REQUEST , INSUFF_RES_ASC ,
3337
- INSUFF_RES_ASCQ );
3338
- return check_condition_result ;
3339
- }
3340
- memset (arr , 0 , rlen );
3364
+ rlen = tlun_cnt * sz_lun ; /* excluding 8 byte header */
3365
+ scsi_set_resid (scp , scsi_bufflen (scp ));
3341
3366
pr_debug ("select_report %d luns = %d wluns = %d no_lun0 %d\n" ,
3342
3367
select_report , lun_cnt , wlun_cnt , sdebug_no_lun_0 );
3343
3368
3344
- /* luns start at byte 8 in response following the header */
3345
- lun_p = (struct scsi_lun * )& arr [8 ];
3346
-
3347
- /* LUNs use single level peripheral device addressing method */
3369
+ /* loops rely on sizeof response header same as sizeof lun (both 8) */
3348
3370
lun = sdebug_no_lun_0 ? 1 : 0 ;
3349
- for (i = 0 ; i < lun_cnt ; i ++ )
3350
- int_to_scsilun (lun ++ , lun_p ++ );
3351
-
3352
- if (wlun_cnt )
3353
- int_to_scsilun (SCSI_W_LUN_REPORT_LUNS , lun_p ++ );
3354
-
3355
- put_unaligned_be32 (rlen - 8 , & arr [0 ]);
3356
-
3357
- res = fill_from_dev_buffer (scp , arr , rlen );
3358
- vfree (arr );
3371
+ for (k = 0 , j = 0 , res = 0 ; true; ++ k , j = 0 ) {
3372
+ memset (arr , 0 , sizeof (arr ));
3373
+ lun_p = (struct scsi_lun * )& arr [0 ];
3374
+ if (k == 0 ) {
3375
+ put_unaligned_be32 (rlen , & arr [0 ]);
3376
+ ++ lun_p ;
3377
+ j = 1 ;
3378
+ }
3379
+ for ( ; j < RL_BUCKET_ELEMS ; ++ j , ++ lun_p ) {
3380
+ if ((k * RL_BUCKET_ELEMS ) + j > lun_cnt )
3381
+ break ;
3382
+ int_to_scsilun (lun ++ , lun_p );
3383
+ }
3384
+ if (j < RL_BUCKET_ELEMS )
3385
+ break ;
3386
+ n = j * sz_lun ;
3387
+ res = p_fill_from_dev_buffer (scp , arr , n , off_rsp );
3388
+ if (res )
3389
+ return res ;
3390
+ off_rsp += n ;
3391
+ }
3392
+ if (wlun_cnt ) {
3393
+ int_to_scsilun (SCSI_W_LUN_REPORT_LUNS , lun_p );
3394
+ ++ j ;
3395
+ }
3396
+ if (j > 0 )
3397
+ res = p_fill_from_dev_buffer (scp , arr , j * sz_lun , off_rsp );
3359
3398
return res ;
3360
3399
}
3361
3400
0 commit comments