diff options
Diffstat (limited to 'drivers/s390/block')
-rw-r--r-- | drivers/s390/block/dasd.c | 194 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 94 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 42 | ||||
-rw-r--r-- | drivers/s390/block/dasd_fba.c | 4 | ||||
-rw-r--r-- | drivers/s390/block/dasd_genhd.c | 14 | ||||
-rw-r--r-- | drivers/s390/block/dasd_ioctl.c | 2 | ||||
-rw-r--r-- | drivers/s390/block/xpram.c | 99 |
7 files changed, 227 insertions, 222 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4bf03fb67f8d..25c1ef6dfd44 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -52,7 +52,7 @@ static void dasd_setup_queue(struct dasd_device * device); | |||
52 | static void dasd_free_queue(struct dasd_device * device); | 52 | static void dasd_free_queue(struct dasd_device * device); |
53 | static void dasd_flush_request_queue(struct dasd_device *); | 53 | static void dasd_flush_request_queue(struct dasd_device *); |
54 | static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); | 54 | static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); |
55 | static void dasd_flush_ccw_queue(struct dasd_device *, int); | 55 | static int dasd_flush_ccw_queue(struct dasd_device *, int); |
56 | static void dasd_tasklet(struct dasd_device *); | 56 | static void dasd_tasklet(struct dasd_device *); |
57 | static void do_kick_device(void *data); | 57 | static void do_kick_device(void *data); |
58 | 58 | ||
@@ -60,6 +60,7 @@ static void do_kick_device(void *data); | |||
60 | * SECTION: Operations on the device structure. | 60 | * SECTION: Operations on the device structure. |
61 | */ | 61 | */ |
62 | static wait_queue_head_t dasd_init_waitq; | 62 | static wait_queue_head_t dasd_init_waitq; |
63 | static wait_queue_head_t dasd_flush_wq; | ||
63 | 64 | ||
64 | /* | 65 | /* |
65 | * Allocate memory for a new device structure. | 66 | * Allocate memory for a new device structure. |
@@ -121,7 +122,7 @@ dasd_free_device(struct dasd_device *device) | |||
121 | /* | 122 | /* |
122 | * Make a new device known to the system. | 123 | * Make a new device known to the system. |
123 | */ | 124 | */ |
124 | static inline int | 125 | static int |
125 | dasd_state_new_to_known(struct dasd_device *device) | 126 | dasd_state_new_to_known(struct dasd_device *device) |
126 | { | 127 | { |
127 | int rc; | 128 | int rc; |
@@ -145,7 +146,7 @@ dasd_state_new_to_known(struct dasd_device *device) | |||
145 | /* | 146 | /* |
146 | * Let the system forget about a device. | 147 | * Let the system forget about a device. |
147 | */ | 148 | */ |
148 | static inline void | 149 | static int |
149 | dasd_state_known_to_new(struct dasd_device * device) | 150 | dasd_state_known_to_new(struct dasd_device * device) |
150 | { | 151 | { |
151 | /* Disable extended error reporting for this device. */ | 152 | /* Disable extended error reporting for this device. */ |
@@ -163,12 +164,13 @@ dasd_state_known_to_new(struct dasd_device * device) | |||
163 | 164 | ||
164 | /* Give up reference we took in dasd_state_new_to_known. */ | 165 | /* Give up reference we took in dasd_state_new_to_known. */ |
165 | dasd_put_device(device); | 166 | dasd_put_device(device); |
167 | return 0; | ||
166 | } | 168 | } |
167 | 169 | ||
168 | /* | 170 | /* |
169 | * Request the irq line for the device. | 171 | * Request the irq line for the device. |
170 | */ | 172 | */ |
171 | static inline int | 173 | static int |
172 | dasd_state_known_to_basic(struct dasd_device * device) | 174 | dasd_state_known_to_basic(struct dasd_device * device) |
173 | { | 175 | { |
174 | int rc; | 176 | int rc; |
@@ -192,17 +194,23 @@ dasd_state_known_to_basic(struct dasd_device * device) | |||
192 | /* | 194 | /* |
193 | * Release the irq line for the device. Terminate any running i/o. | 195 | * Release the irq line for the device. Terminate any running i/o. |
194 | */ | 196 | */ |
195 | static inline void | 197 | static int |
196 | dasd_state_basic_to_known(struct dasd_device * device) | 198 | dasd_state_basic_to_known(struct dasd_device * device) |
197 | { | 199 | { |
200 | int rc; | ||
201 | |||
198 | dasd_gendisk_free(device); | 202 | dasd_gendisk_free(device); |
199 | dasd_flush_ccw_queue(device, 1); | 203 | rc = dasd_flush_ccw_queue(device, 1); |
204 | if (rc) | ||
205 | return rc; | ||
206 | |||
200 | DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); | 207 | DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); |
201 | if (device->debug_area != NULL) { | 208 | if (device->debug_area != NULL) { |
202 | debug_unregister(device->debug_area); | 209 | debug_unregister(device->debug_area); |
203 | device->debug_area = NULL; | 210 | device->debug_area = NULL; |
204 | } | 211 | } |
205 | device->state = DASD_STATE_KNOWN; | 212 | device->state = DASD_STATE_KNOWN; |
213 | return 0; | ||
206 | } | 214 | } |
207 | 215 | ||
208 | /* | 216 | /* |
@@ -219,7 +227,7 @@ dasd_state_basic_to_known(struct dasd_device * device) | |||
219 | * In case the analysis returns an error, the device setup is stopped | 227 | * In case the analysis returns an error, the device setup is stopped |
220 | * (a fake disk was already added to allow formatting). | 228 | * (a fake disk was already added to allow formatting). |
221 | */ | 229 | */ |
222 | static inline int | 230 | static int |
223 | dasd_state_basic_to_ready(struct dasd_device * device) | 231 | dasd_state_basic_to_ready(struct dasd_device * device) |
224 | { | 232 | { |
225 | int rc; | 233 | int rc; |
@@ -247,25 +255,31 @@ dasd_state_basic_to_ready(struct dasd_device * device) | |||
247 | * Forget format information. Check if the target level is basic | 255 | * Forget format information. Check if the target level is basic |
248 | * and if it is create fake disk for formatting. | 256 | * and if it is create fake disk for formatting. |
249 | */ | 257 | */ |
250 | static inline void | 258 | static int |
251 | dasd_state_ready_to_basic(struct dasd_device * device) | 259 | dasd_state_ready_to_basic(struct dasd_device * device) |
252 | { | 260 | { |
253 | dasd_flush_ccw_queue(device, 0); | 261 | int rc; |
262 | |||
263 | rc = dasd_flush_ccw_queue(device, 0); | ||
264 | if (rc) | ||
265 | return rc; | ||
254 | dasd_destroy_partitions(device); | 266 | dasd_destroy_partitions(device); |
255 | dasd_flush_request_queue(device); | 267 | dasd_flush_request_queue(device); |
256 | device->blocks = 0; | 268 | device->blocks = 0; |
257 | device->bp_block = 0; | 269 | device->bp_block = 0; |
258 | device->s2b_shift = 0; | 270 | device->s2b_shift = 0; |
259 | device->state = DASD_STATE_BASIC; | 271 | device->state = DASD_STATE_BASIC; |
272 | return 0; | ||
260 | } | 273 | } |
261 | 274 | ||
262 | /* | 275 | /* |
263 | * Back to basic. | 276 | * Back to basic. |
264 | */ | 277 | */ |
265 | static inline void | 278 | static int |
266 | dasd_state_unfmt_to_basic(struct dasd_device * device) | 279 | dasd_state_unfmt_to_basic(struct dasd_device * device) |
267 | { | 280 | { |
268 | device->state = DASD_STATE_BASIC; | 281 | device->state = DASD_STATE_BASIC; |
282 | return 0; | ||
269 | } | 283 | } |
270 | 284 | ||
271 | /* | 285 | /* |
@@ -273,7 +287,7 @@ dasd_state_unfmt_to_basic(struct dasd_device * device) | |||
273 | * the requeueing of requests from the linux request queue to the | 287 | * the requeueing of requests from the linux request queue to the |
274 | * ccw queue. | 288 | * ccw queue. |
275 | */ | 289 | */ |
276 | static inline int | 290 | static int |
277 | dasd_state_ready_to_online(struct dasd_device * device) | 291 | dasd_state_ready_to_online(struct dasd_device * device) |
278 | { | 292 | { |
279 | device->state = DASD_STATE_ONLINE; | 293 | device->state = DASD_STATE_ONLINE; |
@@ -284,16 +298,17 @@ dasd_state_ready_to_online(struct dasd_device * device) | |||
284 | /* | 298 | /* |
285 | * Stop the requeueing of requests again. | 299 | * Stop the requeueing of requests again. |
286 | */ | 300 | */ |
287 | static inline void | 301 | static int |
288 | dasd_state_online_to_ready(struct dasd_device * device) | 302 | dasd_state_online_to_ready(struct dasd_device * device) |
289 | { | 303 | { |
290 | device->state = DASD_STATE_READY; | 304 | device->state = DASD_STATE_READY; |
305 | return 0; | ||
291 | } | 306 | } |
292 | 307 | ||
293 | /* | 308 | /* |
294 | * Device startup state changes. | 309 | * Device startup state changes. |
295 | */ | 310 | */ |
296 | static inline int | 311 | static int |
297 | dasd_increase_state(struct dasd_device *device) | 312 | dasd_increase_state(struct dasd_device *device) |
298 | { | 313 | { |
299 | int rc; | 314 | int rc; |
@@ -329,30 +344,37 @@ dasd_increase_state(struct dasd_device *device) | |||
329 | /* | 344 | /* |
330 | * Device shutdown state changes. | 345 | * Device shutdown state changes. |
331 | */ | 346 | */ |
332 | static inline int | 347 | static int |
333 | dasd_decrease_state(struct dasd_device *device) | 348 | dasd_decrease_state(struct dasd_device *device) |
334 | { | 349 | { |
350 | int rc; | ||
351 | |||
352 | rc = 0; | ||
335 | if (device->state == DASD_STATE_ONLINE && | 353 | if (device->state == DASD_STATE_ONLINE && |
336 | device->target <= DASD_STATE_READY) | 354 | device->target <= DASD_STATE_READY) |
337 | dasd_state_online_to_ready(device); | 355 | rc = dasd_state_online_to_ready(device); |
338 | 356 | ||
339 | if (device->state == DASD_STATE_READY && | 357 | if (!rc && |
358 | device->state == DASD_STATE_READY && | ||
340 | device->target <= DASD_STATE_BASIC) | 359 | device->target <= DASD_STATE_BASIC) |
341 | dasd_state_ready_to_basic(device); | 360 | rc = dasd_state_ready_to_basic(device); |
342 | 361 | ||
343 | if (device->state == DASD_STATE_UNFMT && | 362 | if (!rc && |
363 | device->state == DASD_STATE_UNFMT && | ||
344 | device->target <= DASD_STATE_BASIC) | 364 | device->target <= DASD_STATE_BASIC) |
345 | dasd_state_unfmt_to_basic(device); | 365 | rc = dasd_state_unfmt_to_basic(device); |
346 | 366 | ||
347 | if (device->state == DASD_STATE_BASIC && | 367 | if (!rc && |
368 | device->state == DASD_STATE_BASIC && | ||
348 | device->target <= DASD_STATE_KNOWN) | 369 | device->target <= DASD_STATE_KNOWN) |
349 | dasd_state_basic_to_known(device); | 370 | rc = dasd_state_basic_to_known(device); |
350 | 371 | ||
351 | if (device->state == DASD_STATE_KNOWN && | 372 | if (!rc && |
373 | device->state == DASD_STATE_KNOWN && | ||
352 | device->target <= DASD_STATE_NEW) | 374 | device->target <= DASD_STATE_NEW) |
353 | dasd_state_known_to_new(device); | 375 | rc = dasd_state_known_to_new(device); |
354 | 376 | ||
355 | return 0; | 377 | return rc; |
356 | } | 378 | } |
357 | 379 | ||
358 | /* | 380 | /* |
@@ -701,6 +723,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr) | |||
701 | cqr->retries--; | 723 | cqr->retries--; |
702 | cqr->status = DASD_CQR_CLEAR; | 724 | cqr->status = DASD_CQR_CLEAR; |
703 | cqr->stopclk = get_clock(); | 725 | cqr->stopclk = get_clock(); |
726 | cqr->starttime = 0; | ||
704 | DBF_DEV_EVENT(DBF_DEBUG, device, | 727 | DBF_DEV_EVENT(DBF_DEBUG, device, |
705 | "terminate cqr %p successful", | 728 | "terminate cqr %p successful", |
706 | cqr); | 729 | cqr); |
@@ -978,6 +1001,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
978 | irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { | 1001 | irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { |
979 | cqr->status = DASD_CQR_QUEUED; | 1002 | cqr->status = DASD_CQR_QUEUED; |
980 | dasd_clear_timer(device); | 1003 | dasd_clear_timer(device); |
1004 | wake_up(&dasd_flush_wq); | ||
981 | dasd_schedule_bh(device); | 1005 | dasd_schedule_bh(device); |
982 | return; | 1006 | return; |
983 | } | 1007 | } |
@@ -1241,6 +1265,10 @@ __dasd_check_expire(struct dasd_device * device) | |||
1241 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); | 1265 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); |
1242 | if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) { | 1266 | if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) { |
1243 | if (time_after_eq(jiffies, cqr->expires + cqr->starttime)) { | 1267 | if (time_after_eq(jiffies, cqr->expires + cqr->starttime)) { |
1268 | DEV_MESSAGE(KERN_ERR, device, | ||
1269 | "internal error - timeout (%is) expired " | ||
1270 | "for cqr %p (%i retries left)", | ||
1271 | (cqr->expires/HZ), cqr, cqr->retries); | ||
1244 | if (device->discipline->term_IO(cqr) != 0) | 1272 | if (device->discipline->term_IO(cqr) != 0) |
1245 | /* Hmpf, try again in 1/10 sec */ | 1273 | /* Hmpf, try again in 1/10 sec */ |
1246 | dasd_set_timer(device, 10); | 1274 | dasd_set_timer(device, 10); |
@@ -1285,46 +1313,100 @@ __dasd_start_head(struct dasd_device * device) | |||
1285 | dasd_set_timer(device, 50); | 1313 | dasd_set_timer(device, 50); |
1286 | } | 1314 | } |
1287 | 1315 | ||
1316 | static inline int | ||
1317 | _wait_for_clear(struct dasd_ccw_req *cqr) | ||
1318 | { | ||
1319 | return (cqr->status == DASD_CQR_QUEUED); | ||
1320 | } | ||
1321 | |||
1288 | /* | 1322 | /* |
1289 | * Remove requests from the ccw queue. | 1323 | * Remove all requests from the ccw queue (all = '1') or only block device |
1324 | * requests in case all = '0'. | ||
1325 | * Take care of the erp-chain (chained via cqr->refers) and remove either | ||
1326 | * the whole erp-chain or none of the erp-requests. | ||
1327 | * If a request is currently running, term_IO is called and the request | ||
1328 | * is re-queued. Prior to removing the terminated request we need to wait | ||
1329 | * for the clear-interrupt. | ||
1330 | * In case termination is not possible we stop processing and just finishing | ||
1331 | * the already moved requests. | ||
1290 | */ | 1332 | */ |
1291 | static void | 1333 | static int |
1292 | dasd_flush_ccw_queue(struct dasd_device * device, int all) | 1334 | dasd_flush_ccw_queue(struct dasd_device * device, int all) |
1293 | { | 1335 | { |
1336 | struct dasd_ccw_req *cqr, *orig, *n; | ||
1337 | int rc, i; | ||
1338 | |||
1294 | struct list_head flush_queue; | 1339 | struct list_head flush_queue; |
1295 | struct list_head *l, *n; | ||
1296 | struct dasd_ccw_req *cqr; | ||
1297 | 1340 | ||
1298 | INIT_LIST_HEAD(&flush_queue); | 1341 | INIT_LIST_HEAD(&flush_queue); |
1299 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | 1342 | spin_lock_irq(get_ccwdev_lock(device->cdev)); |
1300 | list_for_each_safe(l, n, &device->ccw_queue) { | 1343 | rc = 0; |
1301 | cqr = list_entry(l, struct dasd_ccw_req, list); | 1344 | restart: |
1345 | list_for_each_entry_safe(cqr, n, &device->ccw_queue, list) { | ||
1346 | /* get original request of erp request-chain */ | ||
1347 | for (orig = cqr; orig->refers != NULL; orig = orig->refers); | ||
1348 | |||
1302 | /* Flush all request or only block device requests? */ | 1349 | /* Flush all request or only block device requests? */ |
1303 | if (all == 0 && cqr->callback == dasd_end_request_cb) | 1350 | if (all == 0 && cqr->callback != dasd_end_request_cb && |
1351 | orig->callback != dasd_end_request_cb) { | ||
1304 | continue; | 1352 | continue; |
1305 | if (cqr->status == DASD_CQR_IN_IO) | 1353 | } |
1306 | device->discipline->term_IO(cqr); | 1354 | /* Check status and move request to flush_queue */ |
1307 | if (cqr->status != DASD_CQR_DONE || | 1355 | switch (cqr->status) { |
1308 | cqr->status != DASD_CQR_FAILED) { | 1356 | case DASD_CQR_IN_IO: |
1309 | cqr->status = DASD_CQR_FAILED; | 1357 | rc = device->discipline->term_IO(cqr); |
1358 | if (rc) { | ||
1359 | /* unable to terminate requeust */ | ||
1360 | DEV_MESSAGE(KERN_ERR, device, | ||
1361 | "dasd flush ccw_queue is unable " | ||
1362 | " to terminate request %p", | ||
1363 | cqr); | ||
1364 | /* stop flush processing */ | ||
1365 | goto finished; | ||
1366 | } | ||
1367 | break; | ||
1368 | case DASD_CQR_QUEUED: | ||
1369 | case DASD_CQR_ERROR: | ||
1370 | /* set request to FAILED */ | ||
1310 | cqr->stopclk = get_clock(); | 1371 | cqr->stopclk = get_clock(); |
1372 | cqr->status = DASD_CQR_FAILED; | ||
1373 | break; | ||
1374 | default: /* do not touch the others */ | ||
1375 | break; | ||
1376 | } | ||
1377 | /* Rechain request (including erp chain) */ | ||
1378 | for (i = 0; cqr != NULL; cqr = cqr->refers, i++) { | ||
1379 | cqr->endclk = get_clock(); | ||
1380 | list_move_tail(&cqr->list, &flush_queue); | ||
1381 | } | ||
1382 | if (i > 1) | ||
1383 | /* moved more than one request - need to restart */ | ||
1384 | goto restart; | ||
1385 | } | ||
1386 | |||
1387 | finished: | ||
1388 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
1389 | /* Now call the callback function of flushed requests */ | ||
1390 | restart_cb: | ||
1391 | list_for_each_entry_safe(cqr, n, &flush_queue, list) { | ||
1392 | if (cqr->status == DASD_CQR_CLEAR) { | ||
1393 | /* wait for clear interrupt! */ | ||
1394 | wait_event(dasd_flush_wq, _wait_for_clear(cqr)); | ||
1395 | cqr->status = DASD_CQR_FAILED; | ||
1311 | } | 1396 | } |
1312 | /* Process finished ERP request. */ | 1397 | /* Process finished ERP request. */ |
1313 | if (cqr->refers) { | 1398 | if (cqr->refers) { |
1314 | __dasd_process_erp(device, cqr); | 1399 | __dasd_process_erp(device, cqr); |
1315 | continue; | 1400 | /* restart list_for_xx loop since dasd_process_erp |
1401 | * might remove multiple elements */ | ||
1402 | goto restart_cb; | ||
1316 | } | 1403 | } |
1317 | /* Rechain request on device request queue */ | 1404 | /* call the callback function */ |
1318 | cqr->endclk = get_clock(); | 1405 | cqr->endclk = get_clock(); |
1319 | list_move_tail(&cqr->list, &flush_queue); | ||
1320 | } | ||
1321 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
1322 | /* Now call the callback function of flushed requests */ | ||
1323 | list_for_each_safe(l, n, &flush_queue) { | ||
1324 | cqr = list_entry(l, struct dasd_ccw_req, list); | ||
1325 | if (cqr->callback != NULL) | 1406 | if (cqr->callback != NULL) |
1326 | (cqr->callback)(cqr, cqr->callback_data); | 1407 | (cqr->callback)(cqr, cqr->callback_data); |
1327 | } | 1408 | } |
1409 | return rc; | ||
1328 | } | 1410 | } |
1329 | 1411 | ||
1330 | /* | 1412 | /* |
@@ -1510,10 +1592,8 @@ dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr) | |||
1510 | if (device->discipline->term_IO) { | 1592 | if (device->discipline->term_IO) { |
1511 | cqr->retries = -1; | 1593 | cqr->retries = -1; |
1512 | device->discipline->term_IO(cqr); | 1594 | device->discipline->term_IO(cqr); |
1513 | /*nished = | 1595 | /* wait (non-interruptible) for final status |
1514 | * wait (non-interruptible) for final status | 1596 | * because signal ist still pending */ |
1515 | * because signal ist still pending | ||
1516 | */ | ||
1517 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | 1597 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); |
1518 | wait_event(wait_q, _wait_for_wakeup(cqr)); | 1598 | wait_event(wait_q, _wait_for_wakeup(cqr)); |
1519 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | 1599 | spin_lock_irq(get_ccwdev_lock(device->cdev)); |
@@ -1546,19 +1626,11 @@ static inline int | |||
1546 | _dasd_term_running_cqr(struct dasd_device *device) | 1626 | _dasd_term_running_cqr(struct dasd_device *device) |
1547 | { | 1627 | { |
1548 | struct dasd_ccw_req *cqr; | 1628 | struct dasd_ccw_req *cqr; |
1549 | int rc; | ||
1550 | 1629 | ||
1551 | if (list_empty(&device->ccw_queue)) | 1630 | if (list_empty(&device->ccw_queue)) |
1552 | return 0; | 1631 | return 0; |
1553 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); | 1632 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); |
1554 | rc = device->discipline->term_IO(cqr); | 1633 | return device->discipline->term_IO(cqr); |
1555 | if (rc == 0) { | ||
1556 | /* termination successful */ | ||
1557 | cqr->status = DASD_CQR_QUEUED; | ||
1558 | cqr->startclk = cqr->stopclk = 0; | ||
1559 | cqr->starttime = 0; | ||
1560 | } | ||
1561 | return rc; | ||
1562 | } | 1634 | } |
1563 | 1635 | ||
1564 | int | 1636 | int |
@@ -1726,12 +1798,9 @@ dasd_flush_request_queue(struct dasd_device * device) | |||
1726 | return; | 1798 | return; |
1727 | 1799 | ||
1728 | spin_lock_irq(&device->request_queue_lock); | 1800 | spin_lock_irq(&device->request_queue_lock); |
1729 | while (!list_empty(&device->request_queue->queue_head)) { | 1801 | while ((req = elv_next_request(device->request_queue))) { |
1730 | req = elv_next_request(device->request_queue); | ||
1731 | if (req == NULL) | ||
1732 | break; | ||
1733 | dasd_end_request(req, 0); | ||
1734 | blkdev_dequeue_request(req); | 1802 | blkdev_dequeue_request(req); |
1803 | dasd_end_request(req, 0); | ||
1735 | } | 1804 | } |
1736 | spin_unlock_irq(&device->request_queue_lock); | 1805 | spin_unlock_irq(&device->request_queue_lock); |
1737 | } | 1806 | } |
@@ -2091,6 +2160,7 @@ dasd_init(void) | |||
2091 | int rc; | 2160 | int rc; |
2092 | 2161 | ||
2093 | init_waitqueue_head(&dasd_init_waitq); | 2162 | init_waitqueue_head(&dasd_init_waitq); |
2163 | init_waitqueue_head(&dasd_flush_wq); | ||
2094 | 2164 | ||
2095 | /* register 'common' DASD debug area, used for all DBF_XXX calls */ | 2165 | /* register 'common' DASD debug area, used for all DBF_XXX calls */ |
2096 | dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long)); | 2166 | dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long)); |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index d7295386821c..9af02c79ce8a 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -48,18 +48,20 @@ struct dasd_devmap { | |||
48 | }; | 48 | }; |
49 | 49 | ||
50 | /* | 50 | /* |
51 | * dasd_servermap is used to store the server_id of all storage servers | 51 | * dasd_server_ssid_map contains a globally unique storage server subsystem ID. |
52 | * accessed by DASD device driver. | 52 | * dasd_server_ssid_list contains the list of all subsystem IDs accessed by |
53 | * the DASD device driver. | ||
53 | */ | 54 | */ |
54 | struct dasd_servermap { | 55 | struct dasd_server_ssid_map { |
55 | struct list_head list; | 56 | struct list_head list; |
56 | struct server_id { | 57 | struct system_id { |
57 | char vendor[4]; | 58 | char vendor[4]; |
58 | char serial[15]; | 59 | char serial[15]; |
60 | __u16 ssid; | ||
59 | } sid; | 61 | } sid; |
60 | }; | 62 | }; |
61 | 63 | ||
62 | static struct list_head dasd_serverlist; | 64 | static struct list_head dasd_server_ssid_list; |
63 | 65 | ||
64 | /* | 66 | /* |
65 | * Parameter parsing functions for dasd= parameter. The syntax is: | 67 | * Parameter parsing functions for dasd= parameter. The syntax is: |
@@ -89,7 +91,7 @@ static char *dasd[256]; | |||
89 | module_param_array(dasd, charp, NULL, 0); | 91 | module_param_array(dasd, charp, NULL, 0); |
90 | 92 | ||
91 | /* | 93 | /* |
92 | * Single spinlock to protect devmap structures and lists. | 94 | * Single spinlock to protect devmap and servermap structures and lists. |
93 | */ | 95 | */ |
94 | static DEFINE_SPINLOCK(dasd_devmap_lock); | 96 | static DEFINE_SPINLOCK(dasd_devmap_lock); |
95 | 97 | ||
@@ -264,8 +266,9 @@ dasd_parse_keyword( char *parsestring ) { | |||
264 | if (dasd_page_cache) | 266 | if (dasd_page_cache) |
265 | return residual_str; | 267 | return residual_str; |
266 | dasd_page_cache = | 268 | dasd_page_cache = |
267 | kmem_cache_create("dasd_page_cache", PAGE_SIZE, 0, | 269 | kmem_cache_create("dasd_page_cache", PAGE_SIZE, |
268 | SLAB_CACHE_DMA, NULL, NULL ); | 270 | PAGE_SIZE, SLAB_CACHE_DMA, |
271 | NULL, NULL ); | ||
269 | if (!dasd_page_cache) | 272 | if (!dasd_page_cache) |
270 | MESSAGE(KERN_WARNING, "%s", "Failed to create slab, " | 273 | MESSAGE(KERN_WARNING, "%s", "Failed to create slab, " |
271 | "fixed buffer mode disabled."); | 274 | "fixed buffer mode disabled."); |
@@ -394,7 +397,7 @@ dasd_add_busid(char *bus_id, int features) | |||
394 | if (!new) | 397 | if (!new) |
395 | return ERR_PTR(-ENOMEM); | 398 | return ERR_PTR(-ENOMEM); |
396 | spin_lock(&dasd_devmap_lock); | 399 | spin_lock(&dasd_devmap_lock); |
397 | devmap = 0; | 400 | devmap = NULL; |
398 | hash = dasd_hash_busid(bus_id); | 401 | hash = dasd_hash_busid(bus_id); |
399 | list_for_each_entry(tmp, &dasd_hashlists[hash], list) | 402 | list_for_each_entry(tmp, &dasd_hashlists[hash], list) |
400 | if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) { | 403 | if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) { |
@@ -406,10 +409,10 @@ dasd_add_busid(char *bus_id, int features) | |||
406 | new->devindex = dasd_max_devindex++; | 409 | new->devindex = dasd_max_devindex++; |
407 | strncpy(new->bus_id, bus_id, BUS_ID_SIZE); | 410 | strncpy(new->bus_id, bus_id, BUS_ID_SIZE); |
408 | new->features = features; | 411 | new->features = features; |
409 | new->device = 0; | 412 | new->device = NULL; |
410 | list_add(&new->list, &dasd_hashlists[hash]); | 413 | list_add(&new->list, &dasd_hashlists[hash]); |
411 | devmap = new; | 414 | devmap = new; |
412 | new = 0; | 415 | new = NULL; |
413 | } | 416 | } |
414 | spin_unlock(&dasd_devmap_lock); | 417 | spin_unlock(&dasd_devmap_lock); |
415 | kfree(new); | 418 | kfree(new); |
@@ -479,7 +482,7 @@ dasd_device_from_devindex(int devindex) | |||
479 | int i; | 482 | int i; |
480 | 483 | ||
481 | spin_lock(&dasd_devmap_lock); | 484 | spin_lock(&dasd_devmap_lock); |
482 | devmap = 0; | 485 | devmap = NULL; |
483 | for (i = 0; (i < 256) && !devmap; i++) | 486 | for (i = 0; (i < 256) && !devmap; i++) |
484 | list_for_each_entry(tmp, &dasd_hashlists[i], list) | 487 | list_for_each_entry(tmp, &dasd_hashlists[i], list) |
485 | if (tmp->devindex == devindex) { | 488 | if (tmp->devindex == devindex) { |
@@ -859,39 +862,6 @@ static struct attribute_group dasd_attr_group = { | |||
859 | }; | 862 | }; |
860 | 863 | ||
861 | /* | 864 | /* |
862 | * Check if the related storage server is already contained in the | ||
863 | * dasd_serverlist. If server is not contained, create new entry. | ||
864 | * Return 0 if server was already in serverlist, | ||
865 | * 1 if the server was added successfully | ||
866 | * <0 in case of error. | ||
867 | */ | ||
868 | static int | ||
869 | dasd_add_server(struct dasd_uid *uid) | ||
870 | { | ||
871 | struct dasd_servermap *new, *tmp; | ||
872 | |||
873 | /* check if server is already contained */ | ||
874 | list_for_each_entry(tmp, &dasd_serverlist, list) | ||
875 | // normale cmp? | ||
876 | if (strncmp(tmp->sid.vendor, uid->vendor, | ||
877 | sizeof(tmp->sid.vendor)) == 0 | ||
878 | && strncmp(tmp->sid.serial, uid->serial, | ||
879 | sizeof(tmp->sid.serial)) == 0) | ||
880 | return 0; | ||
881 | |||
882 | new = (struct dasd_servermap *) | ||
883 | kzalloc(sizeof(struct dasd_servermap), GFP_KERNEL); | ||
884 | if (!new) | ||
885 | return -ENOMEM; | ||
886 | |||
887 | strncpy(new->sid.vendor, uid->vendor, sizeof(new->sid.vendor)); | ||
888 | strncpy(new->sid.serial, uid->serial, sizeof(new->sid.serial)); | ||
889 | list_add(&new->list, &dasd_serverlist); | ||
890 | return 1; | ||
891 | } | ||
892 | |||
893 | |||
894 | /* | ||
895 | * Return copy of the device unique identifier. | 865 | * Return copy of the device unique identifier. |
896 | */ | 866 | */ |
897 | int | 867 | int |
@@ -910,6 +880,9 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) | |||
910 | 880 | ||
911 | /* | 881 | /* |
912 | * Register the given device unique identifier into devmap struct. | 882 | * Register the given device unique identifier into devmap struct. |
883 | * In addition check if the related storage server subsystem ID is already | ||
884 | * contained in the dasd_server_ssid_list. If subsystem ID is not contained, | ||
885 | * create new entry. | ||
913 | * Return 0 if server was already in serverlist, | 886 | * Return 0 if server was already in serverlist, |
914 | * 1 if the server was added successful | 887 | * 1 if the server was added successful |
915 | * <0 in case of error. | 888 | * <0 in case of error. |
@@ -918,16 +891,39 @@ int | |||
918 | dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) | 891 | dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) |
919 | { | 892 | { |
920 | struct dasd_devmap *devmap; | 893 | struct dasd_devmap *devmap; |
921 | int rc; | 894 | struct dasd_server_ssid_map *srv, *tmp; |
922 | 895 | ||
923 | devmap = dasd_find_busid(cdev->dev.bus_id); | 896 | devmap = dasd_find_busid(cdev->dev.bus_id); |
924 | if (IS_ERR(devmap)) | 897 | if (IS_ERR(devmap)) |
925 | return PTR_ERR(devmap); | 898 | return PTR_ERR(devmap); |
899 | |||
900 | /* generate entry for server_ssid_map */ | ||
901 | srv = (struct dasd_server_ssid_map *) | ||
902 | kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL); | ||
903 | if (!srv) | ||
904 | return -ENOMEM; | ||
905 | strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1); | ||
906 | strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1); | ||
907 | srv->sid.ssid = uid->ssid; | ||
908 | |||
909 | /* server is already contained ? */ | ||
926 | spin_lock(&dasd_devmap_lock); | 910 | spin_lock(&dasd_devmap_lock); |
927 | devmap->uid = *uid; | 911 | devmap->uid = *uid; |
928 | rc = dasd_add_server(uid); | 912 | list_for_each_entry(tmp, &dasd_server_ssid_list, list) { |
913 | if (!memcmp(&srv->sid, &tmp->sid, | ||
914 | sizeof(struct system_id))) { | ||
915 | kfree(srv); | ||
916 | srv = NULL; | ||
917 | break; | ||
918 | } | ||
919 | } | ||
920 | |||
921 | /* add servermap to serverlist */ | ||
922 | if (srv) | ||
923 | list_add(&srv->list, &dasd_server_ssid_list); | ||
929 | spin_unlock(&dasd_devmap_lock); | 924 | spin_unlock(&dasd_devmap_lock); |
930 | return rc; | 925 | |
926 | return (srv ? 1 : 0); | ||
931 | } | 927 | } |
932 | EXPORT_SYMBOL_GPL(dasd_set_uid); | 928 | EXPORT_SYMBOL_GPL(dasd_set_uid); |
933 | 929 | ||
@@ -995,7 +991,7 @@ dasd_devmap_init(void) | |||
995 | INIT_LIST_HEAD(&dasd_hashlists[i]); | 991 | INIT_LIST_HEAD(&dasd_hashlists[i]); |
996 | 992 | ||
997 | /* Initialize servermap structure. */ | 993 | /* Initialize servermap structure. */ |
998 | INIT_LIST_HEAD(&dasd_serverlist); | 994 | INIT_LIST_HEAD(&dasd_server_ssid_list); |
999 | return 0; | 995 | return 0; |
1000 | } | 996 | } |
1001 | 997 | ||
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 2e655f466743..b7a7fac3f7c3 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -65,16 +65,16 @@ struct dasd_eckd_private { | |||
65 | /* The ccw bus type uses this table to find devices that it sends to | 65 | /* The ccw bus type uses this table to find devices that it sends to |
66 | * dasd_eckd_probe */ | 66 | * dasd_eckd_probe */ |
67 | static struct ccw_device_id dasd_eckd_ids[] = { | 67 | static struct ccw_device_id dasd_eckd_ids[] = { |
68 | { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), driver_info: 0x1}, | 68 | { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), .driver_info = 0x1}, |
69 | { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), driver_info: 0x2}, | 69 | { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), .driver_info = 0x2}, |
70 | { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), driver_info: 0x3}, | 70 | { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), .driver_info = 0x3}, |
71 | { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), driver_info: 0x4}, | 71 | { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), .driver_info = 0x4}, |
72 | { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), driver_info: 0x5}, | 72 | { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), .driver_info = 0x5}, |
73 | { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), driver_info: 0x6}, | 73 | { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), .driver_info = 0x6}, |
74 | { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), driver_info: 0x7}, | 74 | { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), .driver_info = 0x7}, |
75 | { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), driver_info: 0x8}, | 75 | { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), .driver_info = 0x8}, |
76 | { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), driver_info: 0x9}, | 76 | { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), .driver_info = 0x9}, |
77 | { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), driver_info: 0xa}, | 77 | { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), .driver_info = 0xa}, |
78 | { /* end of list */ }, | 78 | { /* end of list */ }, |
79 | }; | 79 | }; |
80 | 80 | ||
@@ -468,11 +468,11 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) | |||
468 | return -ENODEV; | 468 | return -ENODEV; |
469 | 469 | ||
470 | memset(uid, 0, sizeof(struct dasd_uid)); | 470 | memset(uid, 0, sizeof(struct dasd_uid)); |
471 | strncpy(uid->vendor, confdata->ned1.HDA_manufacturer, | 471 | memcpy(uid->vendor, confdata->ned1.HDA_manufacturer, |
472 | sizeof(uid->vendor) - 1); | 472 | sizeof(uid->vendor) - 1); |
473 | EBCASC(uid->vendor, sizeof(uid->vendor) - 1); | 473 | EBCASC(uid->vendor, sizeof(uid->vendor) - 1); |
474 | strncpy(uid->serial, confdata->ned1.HDA_location, | 474 | memcpy(uid->serial, confdata->ned1.HDA_location, |
475 | sizeof(uid->serial) - 1); | 475 | sizeof(uid->serial) - 1); |
476 | EBCASC(uid->serial, sizeof(uid->serial) - 1); | 476 | EBCASC(uid->serial, sizeof(uid->serial) - 1); |
477 | uid->ssid = confdata->neq.subsystemID; | 477 | uid->ssid = confdata->neq.subsystemID; |
478 | if (confdata->ned2.sneq.flags == 0x40) { | 478 | if (confdata->ned2.sneq.flags == 0x40) { |
@@ -607,7 +607,7 @@ dasd_eckd_psf_ssc(struct dasd_device *device) | |||
607 | * Valide storage server of current device. | 607 | * Valide storage server of current device. |
608 | */ | 608 | */ |
609 | static int | 609 | static int |
610 | dasd_eckd_validate_server(struct dasd_device *device) | 610 | dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid) |
611 | { | 611 | { |
612 | int rc; | 612 | int rc; |
613 | 613 | ||
@@ -616,11 +616,11 @@ dasd_eckd_validate_server(struct dasd_device *device) | |||
616 | return 0; | 616 | return 0; |
617 | 617 | ||
618 | rc = dasd_eckd_psf_ssc(device); | 618 | rc = dasd_eckd_psf_ssc(device); |
619 | if (rc) | 619 | /* may be requested feature is not available on server, |
620 | /* may be requested feature is not available on server, | 620 | * therefore just report error and go ahead */ |
621 | * therefore just report error and go ahead */ | 621 | DEV_MESSAGE(KERN_INFO, device, |
622 | DEV_MESSAGE(KERN_INFO, device, | 622 | "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d", |
623 | "Perform Subsystem Function returned rc=%d", rc); | 623 | uid->vendor, uid->serial, uid->ssid, rc); |
624 | /* RE-Read Configuration Data */ | 624 | /* RE-Read Configuration Data */ |
625 | return dasd_eckd_read_conf(device); | 625 | return dasd_eckd_read_conf(device); |
626 | } | 626 | } |
@@ -666,7 +666,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
666 | return rc; | 666 | return rc; |
667 | rc = dasd_set_uid(device->cdev, &uid); | 667 | rc = dasd_set_uid(device->cdev, &uid); |
668 | if (rc == 1) /* new server found */ | 668 | if (rc == 1) /* new server found */ |
669 | rc = dasd_eckd_validate_server(device); | 669 | rc = dasd_eckd_validate_server(device, &uid); |
670 | if (rc) | 670 | if (rc) |
671 | return rc; | 671 | return rc; |
672 | 672 | ||
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 808434d38526..e85015be109b 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -44,8 +44,8 @@ struct dasd_fba_private { | |||
44 | }; | 44 | }; |
45 | 45 | ||
46 | static struct ccw_device_id dasd_fba_ids[] = { | 46 | static struct ccw_device_id dasd_fba_ids[] = { |
47 | { CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), driver_info: 0x1}, | 47 | { CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), .driver_info = 0x1}, |
48 | { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), driver_info: 0x2}, | 48 | { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), .driver_info = 0x2}, |
49 | { /* end of list */ }, | 49 | { /* end of list */ }, |
50 | }; | 50 | }; |
51 | 51 | ||
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 12c7d296eaa8..d163632101d2 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c | |||
@@ -83,10 +83,12 @@ dasd_gendisk_alloc(struct dasd_device *device) | |||
83 | void | 83 | void |
84 | dasd_gendisk_free(struct dasd_device *device) | 84 | dasd_gendisk_free(struct dasd_device *device) |
85 | { | 85 | { |
86 | del_gendisk(device->gdp); | 86 | if (device->gdp) { |
87 | device->gdp->queue = 0; | 87 | del_gendisk(device->gdp); |
88 | put_disk(device->gdp); | 88 | device->gdp->queue = NULL; |
89 | device->gdp = 0; | 89 | put_disk(device->gdp); |
90 | device->gdp = NULL; | ||
91 | } | ||
90 | } | 92 | } |
91 | 93 | ||
92 | /* | 94 | /* |
@@ -136,7 +138,7 @@ dasd_destroy_partitions(struct dasd_device * device) | |||
136 | * device->bdev to lower the offline open_count limit again. | 138 | * device->bdev to lower the offline open_count limit again. |
137 | */ | 139 | */ |
138 | bdev = device->bdev; | 140 | bdev = device->bdev; |
139 | device->bdev = 0; | 141 | device->bdev = NULL; |
140 | 142 | ||
141 | /* | 143 | /* |
142 | * See fs/partition/check.c:delete_partition | 144 | * See fs/partition/check.c:delete_partition |
@@ -145,7 +147,7 @@ dasd_destroy_partitions(struct dasd_device * device) | |||
145 | */ | 147 | */ |
146 | memset(&bpart, 0, sizeof(struct blkpg_partition)); | 148 | memset(&bpart, 0, sizeof(struct blkpg_partition)); |
147 | memset(&barg, 0, sizeof(struct blkpg_ioctl_arg)); | 149 | memset(&barg, 0, sizeof(struct blkpg_ioctl_arg)); |
148 | barg.data = &bpart; | 150 | barg.data = (void __user *) &bpart; |
149 | barg.op = BLKPG_DEL_PARTITION; | 151 | barg.op = BLKPG_DEL_PARTITION; |
150 | for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--) | 152 | for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--) |
151 | ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg); | 153 | ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg); |
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index e97f5316ad2d..8fed3603e9ea 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c | |||
@@ -345,7 +345,7 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) | |||
345 | if (bdev != bdev->bd_contains) | 345 | if (bdev != bdev->bd_contains) |
346 | // ro setting is not allowed for partitions | 346 | // ro setting is not allowed for partitions |
347 | return -EINVAL; | 347 | return -EINVAL; |
348 | if (get_user(intval, (int *)argp)) | 348 | if (get_user(intval, (int __user *)argp)) |
349 | return -EFAULT; | 349 | return -EFAULT; |
350 | 350 | ||
351 | set_disk_ro(bdev->bd_disk, intval); | 351 | set_disk_ro(bdev->bd_disk, intval); |
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 4c1e56b9b98d..ca7d51f7eccc 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c | |||
@@ -48,15 +48,6 @@ | |||
48 | #define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x) | 48 | #define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x) |
49 | 49 | ||
50 | 50 | ||
51 | static struct sysdev_class xpram_sysclass = { | ||
52 | set_kset_name("xpram"), | ||
53 | }; | ||
54 | |||
55 | static struct sys_device xpram_sys_device = { | ||
56 | .id = 0, | ||
57 | .cls = &xpram_sysclass, | ||
58 | }; | ||
59 | |||
60 | typedef struct { | 51 | typedef struct { |
61 | unsigned int size; /* size of xpram segment in pages */ | 52 | unsigned int size; /* size of xpram segment in pages */ |
62 | unsigned int offset; /* start page of xpram segment */ | 53 | unsigned int offset; /* start page of xpram segment */ |
@@ -71,11 +62,11 @@ static int xpram_devs; | |||
71 | /* | 62 | /* |
72 | * Parameter parsing functions. | 63 | * Parameter parsing functions. |
73 | */ | 64 | */ |
74 | static int devs = XPRAM_DEVS; | 65 | static int __initdata devs = XPRAM_DEVS; |
75 | static unsigned int sizes[XPRAM_MAX_DEVS]; | 66 | static char __initdata *sizes[XPRAM_MAX_DEVS]; |
76 | 67 | ||
77 | module_param(devs, int, 0); | 68 | module_param(devs, int, 0); |
78 | module_param_array(sizes, int, NULL, 0); | 69 | module_param_array(sizes, charp, NULL, 0); |
79 | 70 | ||
80 | MODULE_PARM_DESC(devs, "number of devices (\"partitions\"), " \ | 71 | MODULE_PARM_DESC(devs, "number of devices (\"partitions\"), " \ |
81 | "the default is " __MODULE_STRING(XPRAM_DEVS) "\n"); | 72 | "the default is " __MODULE_STRING(XPRAM_DEVS) "\n"); |
@@ -86,59 +77,6 @@ MODULE_PARM_DESC(sizes, "list of device (partition) sizes " \ | |||
86 | "claimed by explicit sizes\n"); | 77 | "claimed by explicit sizes\n"); |
87 | MODULE_LICENSE("GPL"); | 78 | MODULE_LICENSE("GPL"); |
88 | 79 | ||
89 | #ifndef MODULE | ||
90 | /* | ||
91 | * Parses the kernel parameters given in the kernel parameter line. | ||
92 | * The expected format is | ||
93 | * <number_of_partitions>[","<partition_size>]* | ||
94 | * where | ||
95 | * devices is a positive integer that initializes xpram_devs | ||
96 | * each size is a non-negative integer possibly followed by a | ||
97 | * magnitude (k,K,m,M,g,G), the list of sizes initialises | ||
98 | * xpram_sizes | ||
99 | * | ||
100 | * Arguments | ||
101 | * str: substring of kernel parameter line that contains xprams | ||
102 | * kernel parameters. | ||
103 | * | ||
104 | * Result 0 on success, -EINVAL else -- only for Version > 2.3 | ||
105 | * | ||
106 | * Side effects | ||
107 | * the global variabls devs is set to the value of | ||
108 | * <number_of_partitions> and sizes[i] is set to the i-th | ||
109 | * partition size (if provided). A parsing error of a value | ||
110 | * results in this value being set to -EINVAL. | ||
111 | */ | ||
112 | static int __init xpram_setup (char *str) | ||
113 | { | ||
114 | char *cp; | ||
115 | int i; | ||
116 | |||
117 | devs = simple_strtoul(str, &cp, 10); | ||
118 | if (cp <= str || devs > XPRAM_MAX_DEVS) | ||
119 | return 0; | ||
120 | for (i = 0; (i < devs) && (*cp++ == ','); i++) { | ||
121 | sizes[i] = simple_strtoul(cp, &cp, 10); | ||
122 | if (*cp == 'g' || *cp == 'G') { | ||
123 | sizes[i] <<= 20; | ||
124 | cp++; | ||
125 | } else if (*cp == 'm' || *cp == 'M') { | ||
126 | sizes[i] <<= 10; | ||
127 | cp++; | ||
128 | } else if (*cp == 'k' || *cp == 'K') | ||
129 | cp++; | ||
130 | while (isspace(*cp)) cp++; | ||
131 | } | ||
132 | if (*cp == ',' && i >= devs) | ||
133 | PRINT_WARN("partition sizes list has too many entries.\n"); | ||
134 | else if (*cp != 0) | ||
135 | PRINT_WARN("ignored '%s' at end of parameter string.\n", cp); | ||
136 | return 1; | ||
137 | } | ||
138 | |||
139 | __setup("xpram_parts=", xpram_setup); | ||
140 | #endif | ||
141 | |||
142 | /* | 80 | /* |
143 | * Copy expanded memory page (4kB) into main memory | 81 | * Copy expanded memory page (4kB) into main memory |
144 | * Arguments | 82 | * Arguments |
@@ -357,6 +295,7 @@ static int __init xpram_setup_sizes(unsigned long pages) | |||
357 | { | 295 | { |
358 | unsigned long mem_needed; | 296 | unsigned long mem_needed; |
359 | unsigned long mem_auto; | 297 | unsigned long mem_auto; |
298 | unsigned long long size; | ||
360 | int mem_auto_no; | 299 | int mem_auto_no; |
361 | int i; | 300 | int i; |
362 | 301 | ||
@@ -374,7 +313,19 @@ static int __init xpram_setup_sizes(unsigned long pages) | |||
374 | mem_needed = 0; | 313 | mem_needed = 0; |
375 | mem_auto_no = 0; | 314 | mem_auto_no = 0; |
376 | for (i = 0; i < xpram_devs; i++) { | 315 | for (i = 0; i < xpram_devs; i++) { |
377 | xpram_sizes[i] = (sizes[i] + 3) & -4UL; | 316 | if (sizes[i]) { |
317 | size = simple_strtoull(sizes[i], &sizes[i], 0); | ||
318 | switch (sizes[i][0]) { | ||
319 | case 'g': | ||
320 | case 'G': | ||
321 | size <<= 20; | ||
322 | break; | ||
323 | case 'm': | ||
324 | case 'M': | ||
325 | size <<= 10; | ||
326 | } | ||
327 | xpram_sizes[i] = (size + 3) & -4UL; | ||
328 | } | ||
378 | if (xpram_sizes[i]) | 329 | if (xpram_sizes[i]) |
379 | mem_needed += xpram_sizes[i]; | 330 | mem_needed += xpram_sizes[i]; |
380 | else | 331 | else |
@@ -491,8 +442,6 @@ static void __exit xpram_exit(void) | |||
491 | } | 442 | } |
492 | unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); | 443 | unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); |
493 | blk_cleanup_queue(xpram_queue); | 444 | blk_cleanup_queue(xpram_queue); |
494 | sysdev_unregister(&xpram_sys_device); | ||
495 | sysdev_class_unregister(&xpram_sysclass); | ||
496 | } | 445 | } |
497 | 446 | ||
498 | static int __init xpram_init(void) | 447 | static int __init xpram_init(void) |
@@ -510,19 +459,7 @@ static int __init xpram_init(void) | |||
510 | rc = xpram_setup_sizes(xpram_pages); | 459 | rc = xpram_setup_sizes(xpram_pages); |
511 | if (rc) | 460 | if (rc) |
512 | return rc; | 461 | return rc; |
513 | rc = sysdev_class_register(&xpram_sysclass); | 462 | return xpram_setup_blkdev(); |
514 | if (rc) | ||
515 | return rc; | ||
516 | |||
517 | rc = sysdev_register(&xpram_sys_device); | ||
518 | if (rc) { | ||
519 | sysdev_class_unregister(&xpram_sysclass); | ||
520 | return rc; | ||
521 | } | ||
522 | rc = xpram_setup_blkdev(); | ||
523 | if (rc) | ||
524 | sysdev_unregister(&xpram_sys_device); | ||
525 | return rc; | ||
526 | } | 463 | } |
527 | 464 | ||
528 | module_init(xpram_init); | 465 | module_init(xpram_init); |