aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorStefan Haberland <stefan.haberland@de.ibm.com>2013-04-15 10:22:23 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-04-17 08:07:34 -0400
commitd42e17129b9f473386d67c6a6549c28bd0e2b52e (patch)
treecc410d624cd4ede3dcc88ac93d6793d8e566fa93 /drivers/s390
parente5dcf0025d7af58f525590ac86ac27cb44714e8d (diff)
s390/dasd: improve speed of dasdfmt
Reorganize format IO requests and enable usage of PAV. Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c109
-rw-r--r--drivers/s390/block/dasd_eckd.c344
-rw-r--r--drivers/s390/block/dasd_int.h10
-rw-r--r--drivers/s390/block/dasd_ioctl.c31
4 files changed, 351 insertions, 143 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index f1b7fdc58a5f..4195cc05efeb 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -246,7 +246,7 @@ static struct dentry *dasd_debugfs_setup(const char *name,
246static int dasd_state_known_to_basic(struct dasd_device *device) 246static int dasd_state_known_to_basic(struct dasd_device *device)
247{ 247{
248 struct dasd_block *block = device->block; 248 struct dasd_block *block = device->block;
249 int rc; 249 int rc = 0;
250 250
251 /* Allocate and register gendisk structure. */ 251 /* Allocate and register gendisk structure. */
252 if (block) { 252 if (block) {
@@ -273,7 +273,8 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
273 DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created"); 273 DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
274 274
275 device->state = DASD_STATE_BASIC; 275 device->state = DASD_STATE_BASIC;
276 return 0; 276
277 return rc;
277} 278}
278 279
279/* 280/*
@@ -282,6 +283,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
282static int dasd_state_basic_to_known(struct dasd_device *device) 283static int dasd_state_basic_to_known(struct dasd_device *device)
283{ 284{
284 int rc; 285 int rc;
286
285 if (device->block) { 287 if (device->block) {
286 dasd_profile_exit(&device->block->profile); 288 dasd_profile_exit(&device->block->profile);
287 if (device->block->debugfs_dentry) 289 if (device->block->debugfs_dentry)
@@ -332,8 +334,10 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
332 if (block->base->discipline->do_analysis != NULL) 334 if (block->base->discipline->do_analysis != NULL)
333 rc = block->base->discipline->do_analysis(block); 335 rc = block->base->discipline->do_analysis(block);
334 if (rc) { 336 if (rc) {
335 if (rc != -EAGAIN) 337 if (rc != -EAGAIN) {
336 device->state = DASD_STATE_UNFMT; 338 device->state = DASD_STATE_UNFMT;
339 goto out;
340 }
337 return rc; 341 return rc;
338 } 342 }
339 dasd_setup_queue(block); 343 dasd_setup_queue(block);
@@ -341,11 +345,16 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
341 block->blocks << block->s2b_shift); 345 block->blocks << block->s2b_shift);
342 device->state = DASD_STATE_READY; 346 device->state = DASD_STATE_READY;
343 rc = dasd_scan_partitions(block); 347 rc = dasd_scan_partitions(block);
344 if (rc) 348 if (rc) {
345 device->state = DASD_STATE_BASIC; 349 device->state = DASD_STATE_BASIC;
350 return rc;
351 }
346 } else { 352 } else {
347 device->state = DASD_STATE_READY; 353 device->state = DASD_STATE_READY;
348 } 354 }
355out:
356 if (device->discipline->basic_to_ready)
357 rc = device->discipline->basic_to_ready(device);
349 return rc; 358 return rc;
350} 359}
351 360
@@ -368,6 +377,11 @@ static int dasd_state_ready_to_basic(struct dasd_device *device)
368{ 377{
369 int rc; 378 int rc;
370 379
380 if (device->discipline->ready_to_basic) {
381 rc = device->discipline->ready_to_basic(device);
382 if (rc)
383 return rc;
384 }
371 device->state = DASD_STATE_BASIC; 385 device->state = DASD_STATE_BASIC;
372 if (device->block) { 386 if (device->block) {
373 struct dasd_block *block = device->block; 387 struct dasd_block *block = device->block;
@@ -402,16 +416,10 @@ static int dasd_state_unfmt_to_basic(struct dasd_device *device)
402static int 416static int
403dasd_state_ready_to_online(struct dasd_device * device) 417dasd_state_ready_to_online(struct dasd_device * device)
404{ 418{
405 int rc;
406 struct gendisk *disk; 419 struct gendisk *disk;
407 struct disk_part_iter piter; 420 struct disk_part_iter piter;
408 struct hd_struct *part; 421 struct hd_struct *part;
409 422
410 if (device->discipline->ready_to_online) {
411 rc = device->discipline->ready_to_online(device);
412 if (rc)
413 return rc;
414 }
415 device->state = DASD_STATE_ONLINE; 423 device->state = DASD_STATE_ONLINE;
416 if (device->block) { 424 if (device->block) {
417 dasd_schedule_block_bh(device->block); 425 dasd_schedule_block_bh(device->block);
@@ -444,6 +452,7 @@ static int dasd_state_online_to_ready(struct dasd_device *device)
444 if (rc) 452 if (rc)
445 return rc; 453 return rc;
446 } 454 }
455
447 device->state = DASD_STATE_READY; 456 device->state = DASD_STATE_READY;
448 if (device->block && !(device->features & DASD_FEATURE_USERAW)) { 457 if (device->block && !(device->features & DASD_FEATURE_USERAW)) {
449 disk = device->block->bdev->bd_disk; 458 disk = device->block->bdev->bd_disk;
@@ -2223,6 +2232,77 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
2223 return rc; 2232 return rc;
2224} 2233}
2225 2234
2235static inline int _wait_for_wakeup_queue(struct list_head *ccw_queue)
2236{
2237 struct dasd_ccw_req *cqr;
2238
2239 list_for_each_entry(cqr, ccw_queue, blocklist) {
2240 if (cqr->callback_data != DASD_SLEEPON_END_TAG)
2241 return 0;
2242 }
2243
2244 return 1;
2245}
2246
2247static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible)
2248{
2249 struct dasd_device *device;
2250 int rc;
2251 struct dasd_ccw_req *cqr, *n;
2252
2253retry:
2254 list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
2255 device = cqr->startdev;
2256 if (cqr->status != DASD_CQR_FILLED) /*could be failed*/
2257 continue;
2258
2259 if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) &&
2260 !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
2261 cqr->status = DASD_CQR_FAILED;
2262 cqr->intrc = -EPERM;
2263 continue;
2264 }
2265 /*Non-temporary stop condition will trigger fail fast*/
2266 if (device->stopped & ~DASD_STOPPED_PENDING &&
2267 test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
2268 !dasd_eer_enabled(device)) {
2269 cqr->status = DASD_CQR_FAILED;
2270 cqr->intrc = -EAGAIN;
2271 continue;
2272 }
2273
2274 /*Don't try to start requests if device is stopped*/
2275 if (interruptible) {
2276 rc = wait_event_interruptible(
2277 generic_waitq, !device->stopped);
2278 if (rc == -ERESTARTSYS) {
2279 cqr->status = DASD_CQR_FAILED;
2280 cqr->intrc = rc;
2281 continue;
2282 }
2283 } else
2284 wait_event(generic_waitq, !(device->stopped));
2285
2286 if (!cqr->callback)
2287 cqr->callback = dasd_wakeup_cb;
2288 cqr->callback_data = DASD_SLEEPON_START_TAG;
2289 dasd_add_request_tail(cqr);
2290 }
2291
2292 wait_event(generic_waitq, _wait_for_wakeup_queue(ccw_queue));
2293
2294 rc = 0;
2295 list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
2296 if (__dasd_sleep_on_erp(cqr))
2297 rc = 1;
2298 }
2299 if (rc)
2300 goto retry;
2301
2302
2303 return 0;
2304}
2305
2226/* 2306/*
2227 * Queue a request to the tail of the device ccw_queue and wait for 2307 * Queue a request to the tail of the device ccw_queue and wait for
2228 * it's completion. 2308 * it's completion.
@@ -2233,6 +2313,15 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr)
2233} 2313}
2234 2314
2235/* 2315/*
2316 * Start requests from a ccw_queue and wait for their completion.
2317 */
2318int dasd_sleep_on_queue(struct list_head *ccw_queue)
2319{
2320 return _dasd_sleep_on_queue(ccw_queue, 0);
2321}
2322EXPORT_SYMBOL(dasd_sleep_on_queue);
2323
2324/*
2236 * Queue a request to the tail of the device ccw_queue and wait 2325 * Queue a request to the tail of the device ccw_queue and wait
2237 * interruptible for it's completion. 2326 * interruptible for it's completion.
2238 */ 2327 */
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 6999fd919e94..6a44b27623ed 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -2022,7 +2022,7 @@ static int dasd_eckd_do_analysis(struct dasd_block *block)
2022 return dasd_eckd_end_analysis(block); 2022 return dasd_eckd_end_analysis(block);
2023} 2023}
2024 2024
2025static int dasd_eckd_ready_to_online(struct dasd_device *device) 2025static int dasd_eckd_basic_to_ready(struct dasd_device *device)
2026{ 2026{
2027 return dasd_alias_add_device(device); 2027 return dasd_alias_add_device(device);
2028}; 2028};
@@ -2031,6 +2031,11 @@ static int dasd_eckd_online_to_ready(struct dasd_device *device)
2031{ 2031{
2032 cancel_work_sync(&device->reload_device); 2032 cancel_work_sync(&device->reload_device);
2033 cancel_work_sync(&device->kick_validate); 2033 cancel_work_sync(&device->kick_validate);
2034 return 0;
2035};
2036
2037static int dasd_eckd_ready_to_basic(struct dasd_device *device)
2038{
2034 return dasd_alias_remove_device(device); 2039 return dasd_alias_remove_device(device);
2035}; 2040};
2036 2041
@@ -2050,45 +2055,34 @@ dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
2050} 2055}
2051 2056
2052static struct dasd_ccw_req * 2057static struct dasd_ccw_req *
2053dasd_eckd_format_device(struct dasd_device * device, 2058dasd_eckd_build_format(struct dasd_device *base,
2054 struct format_data_t * fdata) 2059 struct format_data_t *fdata)
2055{ 2060{
2056 struct dasd_eckd_private *private; 2061 struct dasd_eckd_private *base_priv;
2062 struct dasd_eckd_private *start_priv;
2063 struct dasd_device *startdev;
2057 struct dasd_ccw_req *fcp; 2064 struct dasd_ccw_req *fcp;
2058 struct eckd_count *ect; 2065 struct eckd_count *ect;
2066 struct ch_t address;
2059 struct ccw1 *ccw; 2067 struct ccw1 *ccw;
2060 void *data; 2068 void *data;
2061 int rpt; 2069 int rpt;
2062 struct ch_t address;
2063 int cplength, datasize; 2070 int cplength, datasize;
2064 int i; 2071 int i, j;
2065 int intensity = 0; 2072 int intensity = 0;
2066 int r0_perm; 2073 int r0_perm;
2074 int nr_tracks;
2067 2075
2068 private = (struct dasd_eckd_private *) device->private; 2076 startdev = dasd_alias_get_start_dev(base);
2069 rpt = recs_per_track(&private->rdc_data, 0, fdata->blksize); 2077 if (!startdev)
2070 set_ch_t(&address, 2078 startdev = base;
2071 fdata->start_unit / private->rdc_data.trk_per_cyl,
2072 fdata->start_unit % private->rdc_data.trk_per_cyl);
2073 2079
2074 /* Sanity checks. */ 2080 start_priv = (struct dasd_eckd_private *) startdev->private;
2075 if (fdata->start_unit >= 2081 base_priv = (struct dasd_eckd_private *) base->private;
2076 (private->real_cyl * private->rdc_data.trk_per_cyl)) { 2082
2077 dev_warn(&device->cdev->dev, "Start track number %d used in " 2083 rpt = recs_per_track(&base_priv->rdc_data, 0, fdata->blksize);
2078 "formatting is too big\n", fdata->start_unit); 2084
2079 return ERR_PTR(-EINVAL); 2085 nr_tracks = fdata->stop_unit - fdata->start_unit + 1;
2080 }
2081 if (fdata->start_unit > fdata->stop_unit) {
2082 dev_warn(&device->cdev->dev, "Start track %d used in "
2083 "formatting exceeds end track\n", fdata->start_unit);
2084 return ERR_PTR(-EINVAL);
2085 }
2086 if (dasd_check_blocksize(fdata->blksize) != 0) {
2087 dev_warn(&device->cdev->dev,
2088 "The DASD cannot be formatted with block size %d\n",
2089 fdata->blksize);
2090 return ERR_PTR(-EINVAL);
2091 }
2092 2086
2093 /* 2087 /*
2094 * fdata->intensity is a bit string that tells us what to do: 2088 * fdata->intensity is a bit string that tells us what to do:
@@ -2106,149 +2100,282 @@ dasd_eckd_format_device(struct dasd_device * device,
2106 r0_perm = 1; 2100 r0_perm = 1;
2107 intensity = fdata->intensity; 2101 intensity = fdata->intensity;
2108 } 2102 }
2103
2109 switch (intensity) { 2104 switch (intensity) {
2110 case 0x00: /* Normal format */ 2105 case 0x00: /* Normal format */
2111 case 0x08: /* Normal format, use cdl. */ 2106 case 0x08: /* Normal format, use cdl. */
2112 cplength = 2 + rpt; 2107 cplength = 2 + (rpt*nr_tracks);
2113 datasize = sizeof(struct DE_eckd_data) + 2108 datasize = sizeof(struct PFX_eckd_data) +
2114 sizeof(struct LO_eckd_data) + 2109 sizeof(struct LO_eckd_data) +
2115 rpt * sizeof(struct eckd_count); 2110 rpt * nr_tracks * sizeof(struct eckd_count);
2116 break; 2111 break;
2117 case 0x01: /* Write record zero and format track. */ 2112 case 0x01: /* Write record zero and format track. */
2118 case 0x09: /* Write record zero and format track, use cdl. */ 2113 case 0x09: /* Write record zero and format track, use cdl. */
2119 cplength = 3 + rpt; 2114 cplength = 2 + rpt * nr_tracks;
2120 datasize = sizeof(struct DE_eckd_data) + 2115 datasize = sizeof(struct PFX_eckd_data) +
2121 sizeof(struct LO_eckd_data) + 2116 sizeof(struct LO_eckd_data) +
2122 sizeof(struct eckd_count) + 2117 sizeof(struct eckd_count) +
2123 rpt * sizeof(struct eckd_count); 2118 rpt * nr_tracks * sizeof(struct eckd_count);
2124 break; 2119 break;
2125 case 0x04: /* Invalidate track. */ 2120 case 0x04: /* Invalidate track. */
2126 case 0x0c: /* Invalidate track, use cdl. */ 2121 case 0x0c: /* Invalidate track, use cdl. */
2127 cplength = 3; 2122 cplength = 3;
2128 datasize = sizeof(struct DE_eckd_data) + 2123 datasize = sizeof(struct PFX_eckd_data) +
2129 sizeof(struct LO_eckd_data) + 2124 sizeof(struct LO_eckd_data) +
2130 sizeof(struct eckd_count); 2125 sizeof(struct eckd_count);
2131 break; 2126 break;
2132 default: 2127 default:
2133 dev_warn(&device->cdev->dev, "An I/O control call used " 2128 dev_warn(&startdev->cdev->dev,
2134 "incorrect flags 0x%x\n", fdata->intensity); 2129 "An I/O control call used incorrect flags 0x%x\n",
2130 fdata->intensity);
2135 return ERR_PTR(-EINVAL); 2131 return ERR_PTR(-EINVAL);
2136 } 2132 }
2137 /* Allocate the format ccw request. */ 2133 /* Allocate the format ccw request. */
2138 fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device); 2134 fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,
2135 datasize, startdev);
2139 if (IS_ERR(fcp)) 2136 if (IS_ERR(fcp))
2140 return fcp; 2137 return fcp;
2141 2138
2139 start_priv->count++;
2142 data = fcp->data; 2140 data = fcp->data;
2143 ccw = fcp->cpaddr; 2141 ccw = fcp->cpaddr;
2144 2142
2145 switch (intensity & ~0x08) { 2143 switch (intensity & ~0x08) {
2146 case 0x00: /* Normal format. */ 2144 case 0x00: /* Normal format. */
2147 define_extent(ccw++, (struct DE_eckd_data *) data, 2145 prefix(ccw++, (struct PFX_eckd_data *) data,
2148 fdata->start_unit, fdata->start_unit, 2146 fdata->start_unit, fdata->stop_unit,
2149 DASD_ECKD_CCW_WRITE_CKD, device); 2147 DASD_ECKD_CCW_WRITE_CKD, base, startdev);
2150 /* grant subsystem permission to format R0 */ 2148 /* grant subsystem permission to format R0 */
2151 if (r0_perm) 2149 if (r0_perm)
2152 ((struct DE_eckd_data *)data)->ga_extended |= 0x04; 2150 ((struct PFX_eckd_data *)data)
2153 data += sizeof(struct DE_eckd_data); 2151 ->define_extent.ga_extended |= 0x04;
2152 data += sizeof(struct PFX_eckd_data);
2154 ccw[-1].flags |= CCW_FLAG_CC; 2153 ccw[-1].flags |= CCW_FLAG_CC;
2155 locate_record(ccw++, (struct LO_eckd_data *) data, 2154 locate_record(ccw++, (struct LO_eckd_data *) data,
2156 fdata->start_unit, 0, rpt, 2155 fdata->start_unit, 0, rpt*nr_tracks,
2157 DASD_ECKD_CCW_WRITE_CKD, device, 2156 DASD_ECKD_CCW_WRITE_CKD, base,
2158 fdata->blksize); 2157 fdata->blksize);
2159 data += sizeof(struct LO_eckd_data); 2158 data += sizeof(struct LO_eckd_data);
2160 break; 2159 break;
2161 case 0x01: /* Write record zero + format track. */ 2160 case 0x01: /* Write record zero + format track. */
2162 define_extent(ccw++, (struct DE_eckd_data *) data, 2161 prefix(ccw++, (struct PFX_eckd_data *) data,
2163 fdata->start_unit, fdata->start_unit, 2162 fdata->start_unit, fdata->stop_unit,
2164 DASD_ECKD_CCW_WRITE_RECORD_ZERO, 2163 DASD_ECKD_CCW_WRITE_RECORD_ZERO,
2165 device); 2164 base, startdev);
2166 data += sizeof(struct DE_eckd_data); 2165 data += sizeof(struct PFX_eckd_data);
2167 ccw[-1].flags |= CCW_FLAG_CC; 2166 ccw[-1].flags |= CCW_FLAG_CC;
2168 locate_record(ccw++, (struct LO_eckd_data *) data, 2167 locate_record(ccw++, (struct LO_eckd_data *) data,
2169 fdata->start_unit, 0, rpt + 1, 2168 fdata->start_unit, 0, rpt * nr_tracks + 1,
2170 DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, 2169 DASD_ECKD_CCW_WRITE_RECORD_ZERO, base,
2171 device->block->bp_block); 2170 base->block->bp_block);
2172 data += sizeof(struct LO_eckd_data); 2171 data += sizeof(struct LO_eckd_data);
2173 break; 2172 break;
2174 case 0x04: /* Invalidate track. */ 2173 case 0x04: /* Invalidate track. */
2175 define_extent(ccw++, (struct DE_eckd_data *) data, 2174 prefix(ccw++, (struct PFX_eckd_data *) data,
2176 fdata->start_unit, fdata->start_unit, 2175 fdata->start_unit, fdata->stop_unit,
2177 DASD_ECKD_CCW_WRITE_CKD, device); 2176 DASD_ECKD_CCW_WRITE_CKD, base, startdev);
2178 data += sizeof(struct DE_eckd_data); 2177 data += sizeof(struct PFX_eckd_data);
2179 ccw[-1].flags |= CCW_FLAG_CC; 2178 ccw[-1].flags |= CCW_FLAG_CC;
2180 locate_record(ccw++, (struct LO_eckd_data *) data, 2179 locate_record(ccw++, (struct LO_eckd_data *) data,
2181 fdata->start_unit, 0, 1, 2180 fdata->start_unit, 0, 1,
2182 DASD_ECKD_CCW_WRITE_CKD, device, 8); 2181 DASD_ECKD_CCW_WRITE_CKD, base, 8);
2183 data += sizeof(struct LO_eckd_data); 2182 data += sizeof(struct LO_eckd_data);
2184 break; 2183 break;
2185 } 2184 }
2186 if (intensity & 0x01) { /* write record zero */ 2185
2187 ect = (struct eckd_count *) data; 2186 for (j = 0; j < nr_tracks; j++) {
2188 data += sizeof(struct eckd_count); 2187 /* calculate cylinder and head for the current track */
2189 ect->cyl = address.cyl; 2188 set_ch_t(&address,
2190 ect->head = address.head; 2189 (fdata->start_unit + j) /
2191 ect->record = 0; 2190 base_priv->rdc_data.trk_per_cyl,
2192 ect->kl = 0; 2191 (fdata->start_unit + j) %
2193 ect->dl = 8; 2192 base_priv->rdc_data.trk_per_cyl);
2194 ccw[-1].flags |= CCW_FLAG_CC; 2193 if (intensity & 0x01) { /* write record zero */
2195 ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
2196 ccw->flags = CCW_FLAG_SLI;
2197 ccw->count = 8;
2198 ccw->cda = (__u32)(addr_t) ect;
2199 ccw++;
2200 }
2201 if ((intensity & ~0x08) & 0x04) { /* erase track */
2202 ect = (struct eckd_count *) data;
2203 data += sizeof(struct eckd_count);
2204 ect->cyl = address.cyl;
2205 ect->head = address.head;
2206 ect->record = 1;
2207 ect->kl = 0;
2208 ect->dl = 0;
2209 ccw[-1].flags |= CCW_FLAG_CC;
2210 ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
2211 ccw->flags = CCW_FLAG_SLI;
2212 ccw->count = 8;
2213 ccw->cda = (__u32)(addr_t) ect;
2214 } else { /* write remaining records */
2215 for (i = 0; i < rpt; i++) {
2216 ect = (struct eckd_count *) data; 2194 ect = (struct eckd_count *) data;
2217 data += sizeof(struct eckd_count); 2195 data += sizeof(struct eckd_count);
2218 ect->cyl = address.cyl; 2196 ect->cyl = address.cyl;
2219 ect->head = address.head; 2197 ect->head = address.head;
2220 ect->record = i + 1; 2198 ect->record = 0;
2221 ect->kl = 0; 2199 ect->kl = 0;
2222 ect->dl = fdata->blksize; 2200 ect->dl = 8;
2223 /* Check for special tracks 0-1 when formatting CDL */
2224 if ((intensity & 0x08) &&
2225 fdata->start_unit == 0) {
2226 if (i < 3) {
2227 ect->kl = 4;
2228 ect->dl = sizes_trk0[i] - 4;
2229 }
2230 }
2231 if ((intensity & 0x08) &&
2232 fdata->start_unit == 1) {
2233 ect->kl = 44;
2234 ect->dl = LABEL_SIZE - 44;
2235 }
2236 ccw[-1].flags |= CCW_FLAG_CC; 2201 ccw[-1].flags |= CCW_FLAG_CC;
2237 ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD; 2202 ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
2238 ccw->flags = CCW_FLAG_SLI; 2203 ccw->flags = CCW_FLAG_SLI;
2239 ccw->count = 8; 2204 ccw->count = 8;
2240 ccw->cda = (__u32)(addr_t) ect; 2205 ccw->cda = (__u32)(addr_t) ect;
2241 ccw++; 2206 ccw++;
2242 } 2207 }
2208 if ((intensity & ~0x08) & 0x04) { /* erase track */
2209 ect = (struct eckd_count *) data;
2210 data += sizeof(struct eckd_count);
2211 ect->cyl = address.cyl;
2212 ect->head = address.head;
2213 ect->record = 1;
2214 ect->kl = 0;
2215 ect->dl = 0;
2216 ccw[-1].flags |= CCW_FLAG_CC;
2217 ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
2218 ccw->flags = CCW_FLAG_SLI;
2219 ccw->count = 8;
2220 ccw->cda = (__u32)(addr_t) ect;
2221 } else { /* write remaining records */
2222 for (i = 0; i < rpt; i++) {
2223 ect = (struct eckd_count *) data;
2224 data += sizeof(struct eckd_count);
2225 ect->cyl = address.cyl;
2226 ect->head = address.head;
2227 ect->record = i + 1;
2228 ect->kl = 0;
2229 ect->dl = fdata->blksize;
2230 /*
2231 * Check for special tracks 0-1
2232 * when formatting CDL
2233 */
2234 if ((intensity & 0x08) &&
2235 fdata->start_unit == 0) {
2236 if (i < 3) {
2237 ect->kl = 4;
2238 ect->dl = sizes_trk0[i] - 4;
2239 }
2240 }
2241 if ((intensity & 0x08) &&
2242 fdata->start_unit == 1) {
2243 ect->kl = 44;
2244 ect->dl = LABEL_SIZE - 44;
2245 }
2246 ccw[-1].flags |= CCW_FLAG_CC;
2247 if (i != 0 || j == 0)
2248 ccw->cmd_code =
2249 DASD_ECKD_CCW_WRITE_CKD;
2250 else
2251 ccw->cmd_code =
2252 DASD_ECKD_CCW_WRITE_CKD_MT;
2253 ccw->flags = CCW_FLAG_SLI;
2254 ccw->count = 8;
2255 ccw->cda = (__u32)(addr_t) ect;
2256 ccw++;
2257 }
2258 }
2243 } 2259 }
2244 fcp->startdev = device; 2260
2245 fcp->memdev = device; 2261 fcp->startdev = startdev;
2262 fcp->memdev = startdev;
2246 fcp->retries = 256; 2263 fcp->retries = 256;
2264 fcp->expires = startdev->default_expires * HZ;
2247 fcp->buildclk = get_tod_clock(); 2265 fcp->buildclk = get_tod_clock();
2248 fcp->status = DASD_CQR_FILLED; 2266 fcp->status = DASD_CQR_FILLED;
2267
2249 return fcp; 2268 return fcp;
2250} 2269}
2251 2270
2271static int
2272dasd_eckd_format_device(struct dasd_device *base,
2273 struct format_data_t *fdata)
2274{
2275 struct dasd_ccw_req *cqr, *n;
2276 struct dasd_block *block;
2277 struct dasd_eckd_private *private;
2278 struct list_head format_queue;
2279 struct dasd_device *device;
2280 int old_stop, format_step;
2281 int step, rc = 0;
2282
2283 block = base->block;
2284 private = (struct dasd_eckd_private *) base->private;
2285
2286 /* Sanity checks. */
2287 if (fdata->start_unit >=
2288 (private->real_cyl * private->rdc_data.trk_per_cyl)) {
2289 dev_warn(&base->cdev->dev,
2290 "Start track number %u used in formatting is too big\n",
2291 fdata->start_unit);
2292 return -EINVAL;
2293 }
2294 if (fdata->stop_unit >=
2295 (private->real_cyl * private->rdc_data.trk_per_cyl)) {
2296 dev_warn(&base->cdev->dev,
2297 "Stop track number %u used in formatting is too big\n",
2298 fdata->stop_unit);
2299 return -EINVAL;
2300 }
2301 if (fdata->start_unit > fdata->stop_unit) {
2302 dev_warn(&base->cdev->dev,
2303 "Start track %u used in formatting exceeds end track\n",
2304 fdata->start_unit);
2305 return -EINVAL;
2306 }
2307 if (dasd_check_blocksize(fdata->blksize) != 0) {
2308 dev_warn(&base->cdev->dev,
2309 "The DASD cannot be formatted with block size %u\n",
2310 fdata->blksize);
2311 return -EINVAL;
2312 }
2313
2314 INIT_LIST_HEAD(&format_queue);
2315 old_stop = fdata->stop_unit;
2316
2317 while (fdata->start_unit <= 1) {
2318 fdata->stop_unit = fdata->start_unit;
2319 cqr = dasd_eckd_build_format(base, fdata);
2320 list_add(&cqr->blocklist, &format_queue);
2321
2322 fdata->stop_unit = old_stop;
2323 fdata->start_unit++;
2324
2325 if (fdata->start_unit > fdata->stop_unit)
2326 goto sleep;
2327 }
2328
2329retry:
2330 format_step = 255 / recs_per_track(&private->rdc_data, 0,
2331 fdata->blksize);
2332 while (fdata->start_unit <= old_stop) {
2333 step = fdata->stop_unit - fdata->start_unit + 1;
2334 if (step > format_step)
2335 fdata->stop_unit = fdata->start_unit + format_step - 1;
2336
2337 cqr = dasd_eckd_build_format(base, fdata);
2338 if (IS_ERR(cqr)) {
2339 if (PTR_ERR(cqr) == -ENOMEM) {
2340 /*
2341 * not enough memory available
2342 * go to out and start requests
2343 * retry after first requests were finished
2344 */
2345 fdata->stop_unit = old_stop;
2346 goto sleep;
2347 } else
2348 return PTR_ERR(cqr);
2349 }
2350 list_add(&cqr->blocklist, &format_queue);
2351
2352 fdata->start_unit = fdata->stop_unit + 1;
2353 fdata->stop_unit = old_stop;
2354 }
2355
2356sleep:
2357 dasd_sleep_on_queue(&format_queue);
2358
2359 list_for_each_entry_safe(cqr, n, &format_queue, blocklist) {
2360 device = cqr->startdev;
2361 private = (struct dasd_eckd_private *) device->private;
2362 if (cqr->status == DASD_CQR_FAILED)
2363 rc = -EIO;
2364 list_del_init(&cqr->blocklist);
2365 dasd_sfree_request(cqr, device);
2366 private->count--;
2367 }
2368
2369 /*
2370 * in case of ENOMEM we need to retry after
2371 * first requests are finished
2372 */
2373 if (fdata->start_unit <= fdata->stop_unit)
2374 goto retry;
2375
2376 return rc;
2377}
2378
2252static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) 2379static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
2253{ 2380{
2254 cqr->status = DASD_CQR_FILLED; 2381 cqr->status = DASD_CQR_FILLED;
@@ -4305,8 +4432,9 @@ static struct dasd_discipline dasd_eckd_discipline = {
4305 .uncheck_device = dasd_eckd_uncheck_device, 4432 .uncheck_device = dasd_eckd_uncheck_device,
4306 .do_analysis = dasd_eckd_do_analysis, 4433 .do_analysis = dasd_eckd_do_analysis,
4307 .verify_path = dasd_eckd_verify_path, 4434 .verify_path = dasd_eckd_verify_path,
4308 .ready_to_online = dasd_eckd_ready_to_online, 4435 .basic_to_ready = dasd_eckd_basic_to_ready,
4309 .online_to_ready = dasd_eckd_online_to_ready, 4436 .online_to_ready = dasd_eckd_online_to_ready,
4437 .ready_to_basic = dasd_eckd_ready_to_basic,
4310 .fill_geometry = dasd_eckd_fill_geometry, 4438 .fill_geometry = dasd_eckd_fill_geometry,
4311 .start_IO = dasd_start_IO, 4439 .start_IO = dasd_start_IO,
4312 .term_IO = dasd_term_IO, 4440 .term_IO = dasd_term_IO,
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 899e3f5a56e5..0785bd9bd5b6 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -300,10 +300,11 @@ struct dasd_discipline {
300 * Last things to do when a device is set online, and first things 300 * Last things to do when a device is set online, and first things
301 * when it is set offline. 301 * when it is set offline.
302 */ 302 */
303 int (*ready_to_online) (struct dasd_device *); 303 int (*basic_to_ready) (struct dasd_device *);
304 int (*online_to_ready) (struct dasd_device *); 304 int (*online_to_ready) (struct dasd_device *);
305 int (*ready_to_basic) (struct dasd_device *);
305 306
306 /* 307 /* (struct dasd_device *);
307 * Device operation functions. build_cp creates a ccw chain for 308 * Device operation functions. build_cp creates a ccw chain for
308 * a block device request, start_io starts the request and 309 * a block device request, start_io starts the request and
309 * term_IO cancels it (e.g. in case of a timeout). format_device 310 * term_IO cancels it (e.g. in case of a timeout). format_device
@@ -317,8 +318,8 @@ struct dasd_discipline {
317 int (*start_IO) (struct dasd_ccw_req *); 318 int (*start_IO) (struct dasd_ccw_req *);
318 int (*term_IO) (struct dasd_ccw_req *); 319 int (*term_IO) (struct dasd_ccw_req *);
319 void (*handle_terminated_request) (struct dasd_ccw_req *); 320 void (*handle_terminated_request) (struct dasd_ccw_req *);
320 struct dasd_ccw_req *(*format_device) (struct dasd_device *, 321 int (*format_device) (struct dasd_device *,
321 struct format_data_t *); 322 struct format_data_t *);
322 int (*free_cp) (struct dasd_ccw_req *, struct request *); 323 int (*free_cp) (struct dasd_ccw_req *, struct request *);
323 324
324 /* 325 /*
@@ -672,6 +673,7 @@ int dasd_term_IO(struct dasd_ccw_req *);
672void dasd_schedule_device_bh(struct dasd_device *); 673void dasd_schedule_device_bh(struct dasd_device *);
673void dasd_schedule_block_bh(struct dasd_block *); 674void dasd_schedule_block_bh(struct dasd_block *);
674int dasd_sleep_on(struct dasd_ccw_req *); 675int dasd_sleep_on(struct dasd_ccw_req *);
676int dasd_sleep_on_queue(struct list_head *);
675int dasd_sleep_on_immediatly(struct dasd_ccw_req *); 677int dasd_sleep_on_immediatly(struct dasd_ccw_req *);
676int dasd_sleep_on_interruptible(struct dasd_ccw_req *); 678int dasd_sleep_on_interruptible(struct dasd_ccw_req *);
677void dasd_device_set_timer(struct dasd_device *, int); 679void dasd_device_set_timer(struct dasd_device *, int);
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 03c0e0444553..8be1b51e9311 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -143,12 +143,12 @@ static int dasd_ioctl_resume(struct dasd_block *block)
143/* 143/*
144 * performs formatting of _device_ according to _fdata_ 144 * performs formatting of _device_ according to _fdata_
145 * Note: The discipline's format_function is assumed to deliver formatting 145 * Note: The discipline's format_function is assumed to deliver formatting
146 * commands to format a single unit of the device. In terms of the ECKD 146 * commands to format multiple units of the device. In terms of the ECKD
147 * devices this means CCWs are generated to format a single track. 147 * devices this means CCWs are generated to format multiple tracks.
148 */ 148 */
149static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) 149static int
150dasd_format(struct dasd_block *block, struct format_data_t *fdata)
150{ 151{
151 struct dasd_ccw_req *cqr;
152 struct dasd_device *base; 152 struct dasd_device *base;
153 int rc; 153 int rc;
154 154
@@ -157,8 +157,8 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
157 return -EPERM; 157 return -EPERM;
158 158
159 if (base->state != DASD_STATE_BASIC) { 159 if (base->state != DASD_STATE_BASIC) {
160 pr_warning("%s: The DASD cannot be formatted while it is " 160 pr_warn("%s: The DASD cannot be formatted while it is enabled\n",
161 "enabled\n", dev_name(&base->cdev->dev)); 161 dev_name(&base->cdev->dev));
162 return -EBUSY; 162 return -EBUSY;
163 } 163 }
164 164
@@ -178,21 +178,10 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
178 bdput(bdev); 178 bdput(bdev);
179 } 179 }
180 180
181 while (fdata->start_unit <= fdata->stop_unit) { 181 rc = base->discipline->format_device(base, fdata);
182 cqr = base->discipline->format_device(base, fdata); 182 if (rc)
183 if (IS_ERR(cqr)) 183 return rc;
184 return PTR_ERR(cqr); 184
185 rc = dasd_sleep_on_interruptible(cqr);
186 dasd_sfree_request(cqr, cqr->memdev);
187 if (rc) {
188 if (rc != -ERESTARTSYS)
189 pr_err("%s: Formatting unit %d failed with "
190 "rc=%d\n", dev_name(&base->cdev->dev),
191 fdata->start_unit, rc);
192 return rc;
193 }
194 fdata->start_unit++;
195 }
196 return 0; 185 return 0;
197} 186}
198 187