@@ -207,6 +207,45 @@ static void set_ch_t(struct ch_t *geo, __u32 cyl, __u8 head)
207
207
geo -> head |= head ;
208
208
}
209
209
210
+ /*
211
+ * calculate failing track from sense data depending if
212
+ * it is an EAV device or not
213
+ */
214
+ static int dasd_eckd_track_from_irb (struct irb * irb , struct dasd_device * device ,
215
+ sector_t * track )
216
+ {
217
+ struct dasd_eckd_private * private = device -> private ;
218
+ u8 * sense = NULL ;
219
+ u32 cyl ;
220
+ u8 head ;
221
+
222
+ sense = dasd_get_sense (irb );
223
+ if (!sense ) {
224
+ DBF_DEV_EVENT (DBF_WARNING , device , "%s" ,
225
+ "ESE error no sense data\n" );
226
+ return - EINVAL ;
227
+ }
228
+ if (!(sense [27 ] & DASD_SENSE_BIT_2 )) {
229
+ DBF_DEV_EVENT (DBF_WARNING , device , "%s" ,
230
+ "ESE error no valid track data\n" );
231
+ return - EINVAL ;
232
+ }
233
+
234
+ if (sense [27 ] & DASD_SENSE_BIT_3 ) {
235
+ /* enhanced addressing */
236
+ cyl = sense [30 ] << 20 ;
237
+ cyl |= (sense [31 ] & 0xF0 ) << 12 ;
238
+ cyl |= sense [28 ] << 8 ;
239
+ cyl |= sense [29 ];
240
+ } else {
241
+ cyl = sense [29 ] << 8 ;
242
+ cyl |= sense [30 ];
243
+ }
244
+ head = sense [31 ] & 0x0F ;
245
+ * track = cyl * private -> rdc_data .trk_per_cyl + head ;
246
+ return 0 ;
247
+ }
248
+
210
249
static int set_timestamp (struct ccw1 * ccw , struct DE_eckd_data * data ,
211
250
struct dasd_device * device )
212
251
{
@@ -2986,22 +3025,57 @@ static int dasd_eckd_format_device(struct dasd_device *base,
2986
3025
0 , NULL );
2987
3026
}
2988
3027
3028
+ static bool test_and_set_format_track (struct dasd_format_entry * to_format ,
3029
+ struct dasd_block * block )
3030
+ {
3031
+ struct dasd_format_entry * format ;
3032
+ unsigned long flags ;
3033
+ bool rc = false;
3034
+
3035
+ spin_lock_irqsave (& block -> format_lock , flags );
3036
+ list_for_each_entry (format , & block -> format_list , list ) {
3037
+ if (format -> track == to_format -> track ) {
3038
+ rc = true;
3039
+ goto out ;
3040
+ }
3041
+ }
3042
+ list_add_tail (& to_format -> list , & block -> format_list );
3043
+
3044
+ out :
3045
+ spin_unlock_irqrestore (& block -> format_lock , flags );
3046
+ return rc ;
3047
+ }
3048
+
3049
+ static void clear_format_track (struct dasd_format_entry * format ,
3050
+ struct dasd_block * block )
3051
+ {
3052
+ unsigned long flags ;
3053
+
3054
+ spin_lock_irqsave (& block -> format_lock , flags );
3055
+ list_del_init (& format -> list );
3056
+ spin_unlock_irqrestore (& block -> format_lock , flags );
3057
+ }
3058
+
2989
3059
/*
2990
3060
* Callback function to free ESE format requests.
2991
3061
*/
2992
3062
static void dasd_eckd_ese_format_cb (struct dasd_ccw_req * cqr , void * data )
2993
3063
{
2994
3064
struct dasd_device * device = cqr -> startdev ;
2995
3065
struct dasd_eckd_private * private = device -> private ;
3066
+ struct dasd_format_entry * format = data ;
2996
3067
3068
+ clear_format_track (format , cqr -> basedev -> block );
2997
3069
private -> count -- ;
2998
3070
dasd_ffree_request (cqr , device );
2999
3071
}
3000
3072
3001
3073
static struct dasd_ccw_req *
3002
- dasd_eckd_ese_format (struct dasd_device * startdev , struct dasd_ccw_req * cqr )
3074
+ dasd_eckd_ese_format (struct dasd_device * startdev , struct dasd_ccw_req * cqr ,
3075
+ struct irb * irb )
3003
3076
{
3004
3077
struct dasd_eckd_private * private ;
3078
+ struct dasd_format_entry * format ;
3005
3079
struct format_data_t fdata ;
3006
3080
unsigned int recs_per_trk ;
3007
3081
struct dasd_ccw_req * fcqr ;
@@ -3011,23 +3085,39 @@ dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr)
3011
3085
struct request * req ;
3012
3086
sector_t first_trk ;
3013
3087
sector_t last_trk ;
3088
+ sector_t curr_trk ;
3014
3089
int rc ;
3015
3090
3016
3091
req = cqr -> callback_data ;
3017
- base = cqr -> block -> base ;
3092
+ block = cqr -> block ;
3093
+ base = block -> base ;
3018
3094
private = base -> private ;
3019
- block = base -> block ;
3020
3095
blksize = block -> bp_block ;
3021
3096
recs_per_trk = recs_per_track (& private -> rdc_data , 0 , blksize );
3097
+ format = & startdev -> format_entry ;
3022
3098
3023
3099
first_trk = blk_rq_pos (req ) >> block -> s2b_shift ;
3024
3100
sector_div (first_trk , recs_per_trk );
3025
3101
last_trk =
3026
3102
(blk_rq_pos (req ) + blk_rq_sectors (req ) - 1 ) >> block -> s2b_shift ;
3027
3103
sector_div (last_trk , recs_per_trk );
3104
+ rc = dasd_eckd_track_from_irb (irb , base , & curr_trk );
3105
+ if (rc )
3106
+ return ERR_PTR (rc );
3028
3107
3029
- fdata .start_unit = first_trk ;
3030
- fdata .stop_unit = last_trk ;
3108
+ if (curr_trk < first_trk || curr_trk > last_trk ) {
3109
+ DBF_DEV_EVENT (DBF_WARNING , startdev ,
3110
+ "ESE error track %llu not within range %llu - %llu\n" ,
3111
+ curr_trk , first_trk , last_trk );
3112
+ return ERR_PTR (- EINVAL );
3113
+ }
3114
+ format -> track = curr_trk ;
3115
+ /* test if track is already in formatting by another thread */
3116
+ if (test_and_set_format_track (format , block ))
3117
+ return ERR_PTR (- EEXIST );
3118
+
3119
+ fdata .start_unit = curr_trk ;
3120
+ fdata .stop_unit = curr_trk ;
3031
3121
fdata .blksize = blksize ;
3032
3122
fdata .intensity = private -> uses_cdl ? DASD_FMT_INT_COMPAT : 0 ;
3033
3123
@@ -3044,36 +3134,95 @@ dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr)
3044
3134
return fcqr ;
3045
3135
3046
3136
fcqr -> callback = dasd_eckd_ese_format_cb ;
3137
+ fcqr -> callback_data = (void * ) format ;
3047
3138
3048
3139
return fcqr ;
3049
3140
}
3050
3141
3051
3142
/*
3052
3143
* When data is read from an unformatted area of an ESE volume, this function
3053
3144
* returns zeroed data and thereby mimics a read of zero data.
3145
+ *
3146
+ * The first unformatted track is the one that got the NRF error, the address is
3147
+ * encoded in the sense data.
3148
+ *
3149
+ * All tracks before have returned valid data and should not be touched.
3150
+ * All tracks after the unformatted track might be formatted or not. This is
3151
+ * currently not known, remember the processed data and return the remainder of
3152
+ * the request to the blocklayer in __dasd_cleanup_cqr().
3054
3153
*/
3055
- static void dasd_eckd_ese_read (struct dasd_ccw_req * cqr )
3154
+ static int dasd_eckd_ese_read (struct dasd_ccw_req * cqr , struct irb * irb )
3056
3155
{
3156
+ struct dasd_eckd_private * private ;
3157
+ sector_t first_trk , last_trk ;
3158
+ sector_t first_blk , last_blk ;
3057
3159
unsigned int blksize , off ;
3160
+ unsigned int recs_per_trk ;
3058
3161
struct dasd_device * base ;
3059
3162
struct req_iterator iter ;
3163
+ struct dasd_block * block ;
3164
+ unsigned int skip_block ;
3165
+ unsigned int blk_count ;
3060
3166
struct request * req ;
3061
3167
struct bio_vec bv ;
3168
+ sector_t curr_trk ;
3169
+ sector_t end_blk ;
3062
3170
char * dst ;
3171
+ int rc ;
3063
3172
3064
3173
req = (struct request * ) cqr -> callback_data ;
3065
3174
base = cqr -> block -> base ;
3066
3175
blksize = base -> block -> bp_block ;
3176
+ block = cqr -> block ;
3177
+ private = base -> private ;
3178
+ skip_block = 0 ;
3179
+ blk_count = 0 ;
3180
+
3181
+ recs_per_trk = recs_per_track (& private -> rdc_data , 0 , blksize );
3182
+ first_trk = first_blk = blk_rq_pos (req ) >> block -> s2b_shift ;
3183
+ sector_div (first_trk , recs_per_trk );
3184
+ last_trk = last_blk =
3185
+ (blk_rq_pos (req ) + blk_rq_sectors (req ) - 1 ) >> block -> s2b_shift ;
3186
+ sector_div (last_trk , recs_per_trk );
3187
+ rc = dasd_eckd_track_from_irb (irb , base , & curr_trk );
3188
+ if (rc )
3189
+ return rc ;
3190
+
3191
+ /* sanity check if the current track from sense data is valid */
3192
+ if (curr_trk < first_trk || curr_trk > last_trk ) {
3193
+ DBF_DEV_EVENT (DBF_WARNING , base ,
3194
+ "ESE error track %llu not within range %llu - %llu\n" ,
3195
+ curr_trk , first_trk , last_trk );
3196
+ return - EINVAL ;
3197
+ }
3198
+
3199
+ /*
3200
+ * if not the first track got the NRF error we have to skip over valid
3201
+ * blocks
3202
+ */
3203
+ if (curr_trk != first_trk )
3204
+ skip_block = curr_trk * recs_per_trk - first_blk ;
3205
+
3206
+ /* we have no information beyond the current track */
3207
+ end_blk = (curr_trk + 1 ) * recs_per_trk ;
3067
3208
3068
3209
rq_for_each_segment (bv , req , iter ) {
3069
3210
dst = page_address (bv .bv_page ) + bv .bv_offset ;
3070
3211
for (off = 0 ; off < bv .bv_len ; off += blksize ) {
3071
- if (dst && rq_data_dir (req ) == READ ) {
3212
+ if (first_blk + blk_count >= end_blk ) {
3213
+ cqr -> proc_bytes = blk_count * blksize ;
3214
+ return 0 ;
3215
+ }
3216
+ if (dst && !skip_block ) {
3072
3217
dst += off ;
3073
3218
memset (dst , 0 , blksize );
3219
+ } else {
3220
+ skip_block -- ;
3074
3221
}
3222
+ blk_count ++ ;
3075
3223
}
3076
3224
}
3225
+ return 0 ;
3077
3226
}
3078
3227
3079
3228
/*
0 commit comments