aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd_eckd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r--drivers/s390/block/dasd_eckd.c126
1 files changed, 69 insertions, 57 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 0eb5e5888c42..69f93e626fd3 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -159,6 +159,14 @@ recs_per_track(struct dasd_eckd_characteristics * rdc,
159 return 0; 159 return 0;
160} 160}
161 161
162static void set_ch_t(struct ch_t *geo, __u32 cyl, __u8 head)
163{
164 geo->cyl = (__u16) cyl;
165 geo->head = cyl >> 16;
166 geo->head <<= 4;
167 geo->head |= head;
168}
169
162static int 170static int
163check_XRC (struct ccw1 *de_ccw, 171check_XRC (struct ccw1 *de_ccw,
164 struct DE_eckd_data *data, 172 struct DE_eckd_data *data,
@@ -186,11 +194,12 @@ check_XRC (struct ccw1 *de_ccw,
186} 194}
187 195
188static int 196static int
189define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, 197define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
190 int totrk, int cmd, struct dasd_device * device) 198 unsigned int totrk, int cmd, struct dasd_device *device)
191{ 199{
192 struct dasd_eckd_private *private; 200 struct dasd_eckd_private *private;
193 struct ch_t geo, beg, end; 201 u32 begcyl, endcyl;
202 u16 heads, beghead, endhead;
194 int rc = 0; 203 int rc = 0;
195 204
196 private = (struct dasd_eckd_private *) device->private; 205 private = (struct dasd_eckd_private *) device->private;
@@ -248,27 +257,24 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
248 && !(private->uses_cdl && trk < 2)) 257 && !(private->uses_cdl && trk < 2))
249 data->ga_extended |= 0x40; /* Regular Data Format Mode */ 258 data->ga_extended |= 0x40; /* Regular Data Format Mode */
250 259
251 geo.cyl = private->rdc_data.no_cyl; 260 heads = private->rdc_data.trk_per_cyl;
252 geo.head = private->rdc_data.trk_per_cyl; 261 begcyl = trk / heads;
253 beg.cyl = trk / geo.head; 262 beghead = trk % heads;
254 beg.head = trk % geo.head; 263 endcyl = totrk / heads;
255 end.cyl = totrk / geo.head; 264 endhead = totrk % heads;
256 end.head = totrk % geo.head;
257 265
258 /* check for sequential prestage - enhance cylinder range */ 266 /* check for sequential prestage - enhance cylinder range */
259 if (data->attributes.operation == DASD_SEQ_PRESTAGE || 267 if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
260 data->attributes.operation == DASD_SEQ_ACCESS) { 268 data->attributes.operation == DASD_SEQ_ACCESS) {
261 269
262 if (end.cyl + private->attrib.nr_cyl < geo.cyl) 270 if (endcyl + private->attrib.nr_cyl < private->real_cyl)
263 end.cyl += private->attrib.nr_cyl; 271 endcyl += private->attrib.nr_cyl;
264 else 272 else
265 end.cyl = (geo.cyl - 1); 273 endcyl = (private->real_cyl - 1);
266 } 274 }
267 275
268 data->beg_ext.cyl = beg.cyl; 276 set_ch_t(&data->beg_ext, begcyl, beghead);
269 data->beg_ext.head = beg.head; 277 set_ch_t(&data->end_ext, endcyl, endhead);
270 data->end_ext.cyl = end.cyl;
271 data->end_ext.head = end.head;
272 return rc; 278 return rc;
273} 279}
274 280
@@ -294,13 +300,14 @@ static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata,
294 return rc; 300 return rc;
295} 301}
296 302
297static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk, 303static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
298 int totrk, int cmd, struct dasd_device *basedev, 304 unsigned int trk, unsigned int totrk, int cmd,
299 struct dasd_device *startdev) 305 struct dasd_device *basedev, struct dasd_device *startdev)
300{ 306{
301 struct dasd_eckd_private *basepriv, *startpriv; 307 struct dasd_eckd_private *basepriv, *startpriv;
302 struct DE_eckd_data *data; 308 struct DE_eckd_data *data;
303 struct ch_t geo, beg, end; 309 u32 begcyl, endcyl;
310 u16 heads, beghead, endhead;
304 int rc = 0; 311 int rc = 0;
305 312
306 basepriv = (struct dasd_eckd_private *) basedev->private; 313 basepriv = (struct dasd_eckd_private *) basedev->private;
@@ -374,33 +381,30 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk,
374 && !(basepriv->uses_cdl && trk < 2)) 381 && !(basepriv->uses_cdl && trk < 2))
375 data->ga_extended |= 0x40; /* Regular Data Format Mode */ 382 data->ga_extended |= 0x40; /* Regular Data Format Mode */
376 383
377 geo.cyl = basepriv->rdc_data.no_cyl; 384 heads = basepriv->rdc_data.trk_per_cyl;
378 geo.head = basepriv->rdc_data.trk_per_cyl; 385 begcyl = trk / heads;
379 beg.cyl = trk / geo.head; 386 beghead = trk % heads;
380 beg.head = trk % geo.head; 387 endcyl = totrk / heads;
381 end.cyl = totrk / geo.head; 388 endhead = totrk % heads;
382 end.head = totrk % geo.head;
383 389
384 /* check for sequential prestage - enhance cylinder range */ 390 /* check for sequential prestage - enhance cylinder range */
385 if (data->attributes.operation == DASD_SEQ_PRESTAGE || 391 if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
386 data->attributes.operation == DASD_SEQ_ACCESS) { 392 data->attributes.operation == DASD_SEQ_ACCESS) {
387 393
388 if (end.cyl + basepriv->attrib.nr_cyl < geo.cyl) 394 if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl)
389 end.cyl += basepriv->attrib.nr_cyl; 395 endcyl += basepriv->attrib.nr_cyl;
390 else 396 else
391 end.cyl = (geo.cyl - 1); 397 endcyl = (basepriv->real_cyl - 1);
392 } 398 }
393 399
394 data->beg_ext.cyl = beg.cyl; 400 set_ch_t(&data->beg_ext, begcyl, beghead);
395 data->beg_ext.head = beg.head; 401 set_ch_t(&data->end_ext, endcyl, endhead);
396 data->end_ext.cyl = end.cyl;
397 data->end_ext.head = end.head;
398 return rc; 402 return rc;
399} 403}
400 404
401static void 405static void
402locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, 406locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk,
403 int rec_on_trk, int no_rec, int cmd, 407 unsigned int rec_on_trk, int no_rec, int cmd,
404 struct dasd_device * device, int reclen) 408 struct dasd_device * device, int reclen)
405{ 409{
406 struct dasd_eckd_private *private; 410 struct dasd_eckd_private *private;
@@ -493,10 +497,11 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
493 default: 497 default:
494 DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); 498 DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd);
495 } 499 }
496 data->seek_addr.cyl = data->search_arg.cyl = 500 set_ch_t(&data->seek_addr,
497 trk / private->rdc_data.trk_per_cyl; 501 trk / private->rdc_data.trk_per_cyl,
498 data->seek_addr.head = data->search_arg.head = 502 trk % private->rdc_data.trk_per_cyl);
499 trk % private->rdc_data.trk_per_cyl; 503 data->search_arg.cyl = data->seek_addr.cyl;
504 data->search_arg.head = data->seek_addr.head;
500 data->search_arg.record = rec_on_trk; 505 data->search_arg.record = rec_on_trk;
501} 506}
502 507
@@ -1002,13 +1007,20 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
1002 "rc=%d", rc); 1007 "rc=%d", rc);
1003 goto out_err3; 1008 goto out_err3;
1004 } 1009 }
1010 /* find the vaild cylinder size */
1011 if (private->rdc_data.no_cyl == LV_COMPAT_CYL &&
1012 private->rdc_data.long_no_cyl)
1013 private->real_cyl = private->rdc_data.long_no_cyl;
1014 else
1015 private->real_cyl = private->rdc_data.no_cyl;
1016
1005 DEV_MESSAGE(KERN_INFO, device, 1017 DEV_MESSAGE(KERN_INFO, device,
1006 "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d", 1018 "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
1007 private->rdc_data.dev_type, 1019 private->rdc_data.dev_type,
1008 private->rdc_data.dev_model, 1020 private->rdc_data.dev_model,
1009 private->rdc_data.cu_type, 1021 private->rdc_data.cu_type,
1010 private->rdc_data.cu_model.model, 1022 private->rdc_data.cu_model.model,
1011 private->rdc_data.no_cyl, 1023 private->real_cyl,
1012 private->rdc_data.trk_per_cyl, 1024 private->rdc_data.trk_per_cyl,
1013 private->rdc_data.sec_per_trk); 1025 private->rdc_data.sec_per_trk);
1014 return 0; 1026 return 0;
@@ -1157,8 +1169,6 @@ dasd_eckd_end_analysis(struct dasd_block *block)
1157 } 1169 }
1158 1170
1159 private->uses_cdl = 1; 1171 private->uses_cdl = 1;
1160 /* Calculate number of blocks/records per track. */
1161 blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
1162 /* Check Track 0 for Compatible Disk Layout */ 1172 /* Check Track 0 for Compatible Disk Layout */
1163 count_area = NULL; 1173 count_area = NULL;
1164 for (i = 0; i < 3; i++) { 1174 for (i = 0; i < 3; i++) {
@@ -1200,14 +1210,14 @@ dasd_eckd_end_analysis(struct dasd_block *block)
1200 block->s2b_shift++; 1210 block->s2b_shift++;
1201 1211
1202 blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); 1212 blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
1203 block->blocks = (private->rdc_data.no_cyl * 1213 block->blocks = (private->real_cyl *
1204 private->rdc_data.trk_per_cyl * 1214 private->rdc_data.trk_per_cyl *
1205 blk_per_trk); 1215 blk_per_trk);
1206 1216
1207 DEV_MESSAGE(KERN_INFO, device, 1217 DEV_MESSAGE(KERN_INFO, device,
1208 "(%dkB blks): %dkB at %dkB/trk %s", 1218 "(%dkB blks): %dkB at %dkB/trk %s",
1209 (block->bp_block >> 10), 1219 (block->bp_block >> 10),
1210 ((private->rdc_data.no_cyl * 1220 ((private->real_cyl *
1211 private->rdc_data.trk_per_cyl * 1221 private->rdc_data.trk_per_cyl *
1212 blk_per_trk * (block->bp_block >> 9)) >> 1), 1222 blk_per_trk * (block->bp_block >> 9)) >> 1),
1213 ((blk_per_trk * block->bp_block) >> 10), 1223 ((blk_per_trk * block->bp_block) >> 10),
@@ -1262,7 +1272,8 @@ dasd_eckd_format_device(struct dasd_device * device,
1262 struct eckd_count *ect; 1272 struct eckd_count *ect;
1263 struct ccw1 *ccw; 1273 struct ccw1 *ccw;
1264 void *data; 1274 void *data;
1265 int rpt, cyl, head; 1275 int rpt;
1276 struct ch_t address;
1266 int cplength, datasize; 1277 int cplength, datasize;
1267 int i; 1278 int i;
1268 int intensity = 0; 1279 int intensity = 0;
@@ -1270,24 +1281,25 @@ dasd_eckd_format_device(struct dasd_device * device,
1270 1281
1271 private = (struct dasd_eckd_private *) device->private; 1282 private = (struct dasd_eckd_private *) device->private;
1272 rpt = recs_per_track(&private->rdc_data, 0, fdata->blksize); 1283 rpt = recs_per_track(&private->rdc_data, 0, fdata->blksize);
1273 cyl = fdata->start_unit / private->rdc_data.trk_per_cyl; 1284 set_ch_t(&address,
1274 head = fdata->start_unit % private->rdc_data.trk_per_cyl; 1285 fdata->start_unit / private->rdc_data.trk_per_cyl,
1286 fdata->start_unit % private->rdc_data.trk_per_cyl);
1275 1287
1276 /* Sanity checks. */ 1288 /* Sanity checks. */
1277 if (fdata->start_unit >= 1289 if (fdata->start_unit >=
1278 (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)) { 1290 (private->real_cyl * private->rdc_data.trk_per_cyl)) {
1279 DEV_MESSAGE(KERN_INFO, device, "Track no %d too big!", 1291 DEV_MESSAGE(KERN_INFO, device, "Track no %u too big!",
1280 fdata->start_unit); 1292 fdata->start_unit);
1281 return ERR_PTR(-EINVAL); 1293 return ERR_PTR(-EINVAL);
1282 } 1294 }
1283 if (fdata->start_unit > fdata->stop_unit) { 1295 if (fdata->start_unit > fdata->stop_unit) {
1284 DEV_MESSAGE(KERN_INFO, device, "Track %d reached! ending.", 1296 DEV_MESSAGE(KERN_INFO, device, "Track %u reached! ending.",
1285 fdata->start_unit); 1297 fdata->start_unit);
1286 return ERR_PTR(-EINVAL); 1298 return ERR_PTR(-EINVAL);
1287 } 1299 }
1288 if (dasd_check_blocksize(fdata->blksize) != 0) { 1300 if (dasd_check_blocksize(fdata->blksize) != 0) {
1289 DEV_MESSAGE(KERN_WARNING, device, 1301 DEV_MESSAGE(KERN_WARNING, device,
1290 "Invalid blocksize %d...terminating!", 1302 "Invalid blocksize %u...terminating!",
1291 fdata->blksize); 1303 fdata->blksize);
1292 return ERR_PTR(-EINVAL); 1304 return ERR_PTR(-EINVAL);
1293 } 1305 }
@@ -1389,8 +1401,8 @@ dasd_eckd_format_device(struct dasd_device * device,
1389 if (intensity & 0x01) { /* write record zero */ 1401 if (intensity & 0x01) { /* write record zero */
1390 ect = (struct eckd_count *) data; 1402 ect = (struct eckd_count *) data;
1391 data += sizeof(struct eckd_count); 1403 data += sizeof(struct eckd_count);
1392 ect->cyl = cyl; 1404 ect->cyl = address.cyl;
1393 ect->head = head; 1405 ect->head = address.head;
1394 ect->record = 0; 1406 ect->record = 0;
1395 ect->kl = 0; 1407 ect->kl = 0;
1396 ect->dl = 8; 1408 ect->dl = 8;
@@ -1404,8 +1416,8 @@ dasd_eckd_format_device(struct dasd_device * device,
1404 if ((intensity & ~0x08) & 0x04) { /* erase track */ 1416 if ((intensity & ~0x08) & 0x04) { /* erase track */
1405 ect = (struct eckd_count *) data; 1417 ect = (struct eckd_count *) data;
1406 data += sizeof(struct eckd_count); 1418 data += sizeof(struct eckd_count);
1407 ect->cyl = cyl; 1419 ect->cyl = address.cyl;
1408 ect->head = head; 1420 ect->head = address.head;
1409 ect->record = 1; 1421 ect->record = 1;
1410 ect->kl = 0; 1422 ect->kl = 0;
1411 ect->dl = 0; 1423 ect->dl = 0;
@@ -1418,8 +1430,8 @@ dasd_eckd_format_device(struct dasd_device * device,
1418 for (i = 0; i < rpt; i++) { 1430 for (i = 0; i < rpt; i++) {
1419 ect = (struct eckd_count *) data; 1431 ect = (struct eckd_count *) data;
1420 data += sizeof(struct eckd_count); 1432 data += sizeof(struct eckd_count);
1421 ect->cyl = cyl; 1433 ect->cyl = address.cyl;
1422 ect->head = head; 1434 ect->head = address.head;
1423 ect->record = i + 1; 1435 ect->record = i + 1;
1424 ect->kl = 0; 1436 ect->kl = 0;
1425 ect->dl = fdata->blksize; 1437 ect->dl = fdata->blksize;