aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Weinhuber <wein@de.ibm.com>2009-03-26 10:23:47 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-03-26 10:24:05 -0400
commitb44b0ab3bac16356f03e94b1b49ba9305710c445 (patch)
tree66dfc19e2164a6a30d19b958ccf4e4a5d210c8d8
parentf9a28f7bc5225af476f8d4bb669038da8801b7c4 (diff)
[S390] dasd: add large volume support
The dasd device driver will now support ECKD devices with more then 65520 cylinders. In the traditional ECKD adressing scheme each track is addressed by a 16-bit cylinder and 16-bit head number. The new addressing scheme makes use of the fact that the actual number of heads is never larger then 15, so 12 bits of the head number can be redefined to be part of the cylinder address. Signed-off-by: Stefan Weinhuber <wein@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/dasd.h10
-rw-r--r--arch/s390/include/asm/vtoc.h16
-rw-r--r--drivers/s390/block/dasd_eckd.c126
-rw-r--r--drivers/s390/block/dasd_eckd.h9
-rw-r--r--drivers/s390/block/dasd_int.h2
-rw-r--r--drivers/s390/block/dasd_ioctl.c4
-rw-r--r--drivers/s390/block/dasd_proc.c2
-rw-r--r--fs/partitions/ibm.c101
8 files changed, 171 insertions, 99 deletions
diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h
index e2db6f16d9c8..218bce81ec70 100644
--- a/arch/s390/include/asm/dasd.h
+++ b/arch/s390/include/asm/dasd.h
@@ -162,15 +162,15 @@ typedef struct dasd_profile_info_t {
162 unsigned int dasd_io_nr_req[32]; /* histogram of # of requests in chanq */ 162 unsigned int dasd_io_nr_req[32]; /* histogram of # of requests in chanq */
163} dasd_profile_info_t; 163} dasd_profile_info_t;
164 164
165/* 165/*
166 * struct format_data_t 166 * struct format_data_t
167 * represents all data necessary to format a dasd 167 * represents all data necessary to format a dasd
168 */ 168 */
169typedef struct format_data_t { 169typedef struct format_data_t {
170 int start_unit; /* from track */ 170 unsigned int start_unit; /* from track */
171 int stop_unit; /* to track */ 171 unsigned int stop_unit; /* to track */
172 int blksize; /* sectorsize */ 172 unsigned int blksize; /* sectorsize */
173 int intensity; 173 unsigned int intensity;
174} format_data_t; 174} format_data_t;
175 175
176/* 176/*
diff --git a/arch/s390/include/asm/vtoc.h b/arch/s390/include/asm/vtoc.h
index 3a5267d90d29..8406a2b3157a 100644
--- a/arch/s390/include/asm/vtoc.h
+++ b/arch/s390/include/asm/vtoc.h
@@ -39,7 +39,7 @@ struct vtoc_labeldate
39 __u16 day; 39 __u16 day;
40} __attribute__ ((packed)); 40} __attribute__ ((packed));
41 41
42struct vtoc_volume_label 42struct vtoc_volume_label_cdl
43{ 43{
44 char volkey[4]; /* volume key = volume label */ 44 char volkey[4]; /* volume key = volume label */
45 char vollbl[4]; /* volume label */ 45 char vollbl[4]; /* volume label */
@@ -56,6 +56,14 @@ struct vtoc_volume_label
56 char res3[29]; /* reserved */ 56 char res3[29]; /* reserved */
57} __attribute__ ((packed)); 57} __attribute__ ((packed));
58 58
59struct vtoc_volume_label_ldl {
60 char vollbl[4]; /* volume label */
61 char volid[6]; /* volume identifier */
62 char res3[69]; /* reserved */
63 char ldl_version; /* version number, valid for ldl format */
64 __u64 formatted_blocks; /* valid when ldl_version >= f2 */
65} __attribute__ ((packed));
66
59struct vtoc_extent 67struct vtoc_extent
60{ 68{
61 __u8 typeind; /* extent type indicator */ 69 __u8 typeind; /* extent type indicator */
@@ -140,7 +148,11 @@ struct vtoc_format4_label
140 char res2[10]; /* reserved */ 148 char res2[10]; /* reserved */
141 __u8 DS4EFLVL; /* extended free-space management level */ 149 __u8 DS4EFLVL; /* extended free-space management level */
142 struct vtoc_cchhb DS4EFPTR; /* pointer to extended free-space info */ 150 struct vtoc_cchhb DS4EFPTR; /* pointer to extended free-space info */
143 char res3[9]; /* reserved */ 151 char res3; /* reserved */
152 __u32 DS4DCYL; /* number of logical cyls */
153 char res4[2]; /* reserved */
154 __u8 DS4DEVF2; /* device flags */
155 char res5; /* reserved */
144} __attribute__ ((packed)); 156} __attribute__ ((packed));
145 157
146struct vtoc_ds5ext 158struct vtoc_ds5ext
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;
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 2476f87d21d0..eecfa776db15 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -48,6 +48,11 @@
48#define PSF_ORDER_PRSSD 0x18 48#define PSF_ORDER_PRSSD 0x18
49#define PSF_ORDER_SSC 0x1D 49#define PSF_ORDER_SSC 0x1D
50 50
51/*
52 * Size that is reportet for large volumes in the old 16-bit no_cyl field
53 */
54#define LV_COMPAT_CYL 0xFFFE
55
51/***************************************************************************** 56/*****************************************************************************
52 * SECTION: Type Definitions 57 * SECTION: Type Definitions
53 ****************************************************************************/ 58 ****************************************************************************/
@@ -228,7 +233,8 @@ struct dasd_eckd_characteristics {
228 __u8 factor7; 233 __u8 factor7;
229 __u8 factor8; 234 __u8 factor8;
230 __u8 reserved2[3]; 235 __u8 reserved2[3];
231 __u8 reserved3[10]; 236 __u8 reserved3[6];
237 __u32 long_no_cyl;
232} __attribute__ ((packed)); 238} __attribute__ ((packed));
233 239
234/* elements of the configuration data */ 240/* elements of the configuration data */
@@ -406,6 +412,7 @@ struct dasd_eckd_private {
406 int uses_cdl; 412 int uses_cdl;
407 struct attrib_data_t attrib; /* e.g. cache operations */ 413 struct attrib_data_t attrib; /* e.g. cache operations */
408 struct dasd_rssd_features features; 414 struct dasd_rssd_features features;
415 u32 real_cyl;
409 416
410 /* alias managemnet */ 417 /* alias managemnet */
411 struct dasd_uid uid; 418 struct dasd_uid uid;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 4a39084d9c95..29991a9fa07a 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -378,7 +378,7 @@ struct dasd_block {
378 struct block_device *bdev; 378 struct block_device *bdev;
379 atomic_t open_count; 379 atomic_t open_count;
380 380
381 unsigned long blocks; /* size of volume in blocks */ 381 unsigned long long blocks; /* size of volume in blocks */
382 unsigned int bp_block; /* bytes per block */ 382 unsigned int bp_block; /* bytes per block */
383 unsigned int s2b_shift; /* log2 (bp_block/512) */ 383 unsigned int s2b_shift; /* log2 (bp_block/512) */
384 384
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 16e6ba462cb6..a3bbdb807bad 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -146,7 +146,7 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
146 } 146 }
147 147
148 DBF_DEV_EVENT(DBF_NOTICE, base, 148 DBF_DEV_EVENT(DBF_NOTICE, base,
149 "formatting units %d to %d (%d B blocks) flags %d", 149 "formatting units %u to %u (%u B blocks) flags %u",
150 fdata->start_unit, 150 fdata->start_unit,
151 fdata->stop_unit, fdata->blksize, fdata->intensity); 151 fdata->stop_unit, fdata->blksize, fdata->intensity);
152 152
@@ -170,7 +170,7 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
170 if (rc) { 170 if (rc) {
171 if (rc != -ERESTARTSYS) 171 if (rc != -ERESTARTSYS)
172 DEV_MESSAGE(KERN_ERR, base, 172 DEV_MESSAGE(KERN_ERR, base,
173 " Formatting of unit %d failed " 173 " Formatting of unit %u failed "
174 "with rc = %d", 174 "with rc = %d",
175 fdata->start_unit, rc); 175 fdata->start_unit, rc);
176 return rc; 176 return rc;
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index bf6fd348f20e..0aa569419d57 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -112,7 +112,7 @@ dasd_devices_show(struct seq_file *m, void *v)
112 seq_printf(m, "n/f "); 112 seq_printf(m, "n/f ");
113 else 113 else
114 seq_printf(m, 114 seq_printf(m,
115 "at blocksize: %d, %ld blocks, %ld MB", 115 "at blocksize: %d, %lld blocks, %lld MB",
116 block->bp_block, block->blocks, 116 block->bp_block, block->blocks,
117 ((block->bp_block >> 9) * 117 ((block->bp_block >> 9) *
118 block->blocks) >> 11); 118 block->blocks) >> 11);
diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c
index 1e064c4a4f86..46297683cd34 100644
--- a/fs/partitions/ibm.c
+++ b/fs/partitions/ibm.c
@@ -21,20 +21,38 @@
21 * compute the block number from a 21 * compute the block number from a
22 * cyl-cyl-head-head structure 22 * cyl-cyl-head-head structure
23 */ 23 */
24static inline int 24static sector_t
25cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) { 25cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) {
26 return ptr->cc * geo->heads * geo->sectors + 26
27 ptr->hh * geo->sectors; 27 sector_t cyl;
28 __u16 head;
29
30 /*decode cylinder and heads for large volumes */
31 cyl = ptr->hh & 0xFFF0;
32 cyl <<= 12;
33 cyl |= ptr->cc;
34 head = ptr->hh & 0x000F;
35 return cyl * geo->heads * geo->sectors +
36 head * geo->sectors;
28} 37}
29 38
30/* 39/*
31 * compute the block number from a 40 * compute the block number from a
32 * cyl-cyl-head-head-block structure 41 * cyl-cyl-head-head-block structure
33 */ 42 */
34static inline int 43static sector_t
35cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) { 44cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) {
36 return ptr->cc * geo->heads * geo->sectors + 45
37 ptr->hh * geo->sectors + 46 sector_t cyl;
47 __u16 head;
48
49 /*decode cylinder and heads for large volumes */
50 cyl = ptr->hh & 0xFFF0;
51 cyl <<= 12;
52 cyl |= ptr->cc;
53 head = ptr->hh & 0x000F;
54 return cyl * geo->heads * geo->sectors +
55 head * geo->sectors +
38 ptr->b; 56 ptr->b;
39} 57}
40 58
@@ -43,14 +61,15 @@ cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) {
43int 61int
44ibm_partition(struct parsed_partitions *state, struct block_device *bdev) 62ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
45{ 63{
46 int blocksize, offset, size,res; 64 int blocksize, res;
47 loff_t i_size; 65 loff_t i_size, offset, size, fmt_size;
48 dasd_information2_t *info; 66 dasd_information2_t *info;
49 struct hd_geometry *geo; 67 struct hd_geometry *geo;
50 char type[5] = {0,}; 68 char type[5] = {0,};
51 char name[7] = {0,}; 69 char name[7] = {0,};
52 union label_t { 70 union label_t {
53 struct vtoc_volume_label vol; 71 struct vtoc_volume_label_cdl vol;
72 struct vtoc_volume_label_ldl lnx;
54 struct vtoc_cms_label cms; 73 struct vtoc_cms_label cms;
55 } *label; 74 } *label;
56 unsigned char *data; 75 unsigned char *data;
@@ -85,14 +104,16 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
85 if (data == NULL) 104 if (data == NULL)
86 goto out_readerr; 105 goto out_readerr;
87 106
88 strncpy (type, data, 4);
89 if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD")))
90 strncpy(name, data + 8, 6);
91 else
92 strncpy(name, data + 4, 6);
93 memcpy(label, data, sizeof(union label_t)); 107 memcpy(label, data, sizeof(union label_t));
94 put_dev_sector(sect); 108 put_dev_sector(sect);
95 109
110 if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) {
111 strncpy(type, label->vol.vollbl, 4);
112 strncpy(name, label->vol.volid, 6);
113 } else {
114 strncpy(type, label->lnx.vollbl, 4);
115 strncpy(name, label->lnx.volid, 6);
116 }
96 EBCASC(type, 4); 117 EBCASC(type, 4);
97 EBCASC(name, 6); 118 EBCASC(name, 6);
98 119
@@ -110,36 +131,54 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
110 /* 131 /*
111 * VM style CMS1 labeled disk 132 * VM style CMS1 labeled disk
112 */ 133 */
134 blocksize = label->cms.block_size;
113 if (label->cms.disk_offset != 0) { 135 if (label->cms.disk_offset != 0) {
114 printk("CMS1/%8s(MDSK):", name); 136 printk("CMS1/%8s(MDSK):", name);
115 /* disk is reserved minidisk */ 137 /* disk is reserved minidisk */
116 blocksize = label->cms.block_size;
117 offset = label->cms.disk_offset; 138 offset = label->cms.disk_offset;
118 size = (label->cms.block_count - 1) 139 size = (label->cms.block_count - 1)
119 * (blocksize >> 9); 140 * (blocksize >> 9);
120 } else { 141 } else {
121 printk("CMS1/%8s:", name); 142 printk("CMS1/%8s:", name);
122 offset = (info->label_block + 1); 143 offset = (info->label_block + 1);
123 size = i_size >> 9; 144 size = label->cms.block_count
145 * (blocksize >> 9);
124 } 146 }
147 put_partition(state, 1, offset*(blocksize >> 9),
148 size-offset*(blocksize >> 9));
125 } else { 149 } else {
126 /* 150 if (strncmp(type, "LNX1", 4) == 0) {
127 * Old style LNX1 or unlabeled disk 151 printk("LNX1/%8s:", name);
128 */ 152 if (label->lnx.ldl_version == 0xf2) {
129 if (strncmp(type, "LNX1", 4) == 0) 153 fmt_size = label->lnx.formatted_blocks
130 printk ("LNX1/%8s:", name); 154 * (blocksize >> 9);
131 else 155 } else if (!strcmp(info->type, "ECKD")) {
156 /* formated w/o large volume support */
157 fmt_size = geo->cylinders * geo->heads
158 * geo->sectors * (blocksize >> 9);
159 } else {
160 /* old label and no usable disk geometry
161 * (e.g. DIAG) */
162 fmt_size = i_size >> 9;
163 }
164 size = i_size >> 9;
165 if (fmt_size < size)
166 size = fmt_size;
167 offset = (info->label_block + 1);
168 } else {
169 /* unlabeled disk */
132 printk("(nonl)"); 170 printk("(nonl)");
133 offset = (info->label_block + 1); 171 size = i_size >> 9;
134 size = i_size >> 9; 172 offset = (info->label_block + 1);
135 } 173 }
136 put_partition(state, 1, offset*(blocksize >> 9), 174 put_partition(state, 1, offset*(blocksize >> 9),
137 size-offset*(blocksize >> 9)); 175 size-offset*(blocksize >> 9));
176 }
138 } else if (info->format == DASD_FORMAT_CDL) { 177 } else if (info->format == DASD_FORMAT_CDL) {
139 /* 178 /*
140 * New style CDL formatted disk 179 * New style CDL formatted disk
141 */ 180 */
142 unsigned int blk; 181 sector_t blk;
143 int counter; 182 int counter;
144 183
145 /* 184 /*
@@ -166,7 +205,8 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
166 /* skip FMT4 / FMT5 / FMT7 labels */ 205 /* skip FMT4 / FMT5 / FMT7 labels */
167 if (f1.DS1FMTID == _ascebc['4'] 206 if (f1.DS1FMTID == _ascebc['4']
168 || f1.DS1FMTID == _ascebc['5'] 207 || f1.DS1FMTID == _ascebc['5']
169 || f1.DS1FMTID == _ascebc['7']) { 208 || f1.DS1FMTID == _ascebc['7']
209 || f1.DS1FMTID == _ascebc['9']) {
170 blk++; 210 blk++;
171 data = read_dev_sector(bdev, blk * 211 data = read_dev_sector(bdev, blk *
172 (blocksize/512), 212 (blocksize/512),
@@ -174,8 +214,9 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
174 continue; 214 continue;
175 } 215 }
176 216
177 /* only FMT1 valid at this point */ 217 /* only FMT1 and 8 labels valid at this point */
178 if (f1.DS1FMTID != _ascebc['1']) 218 if (f1.DS1FMTID != _ascebc['1'] &&
219 f1.DS1FMTID != _ascebc['8'])
179 break; 220 break;
180 221
181 /* OK, we got valid partition data */ 222 /* OK, we got valid partition data */