upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.git] / drivers / s390 / block / dasd_fba.c
1 /* 
2  * File...........: linux/drivers/s390/block/dasd_fba.c
3  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4  * Bugreports.to..: <Linux390@de.ibm.com>
5  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
6  *
7  * $Revision: 1.37 $
8  */
9
10 #include <linux/config.h>
11 #include <linux/stddef.h>
12 #include <linux/kernel.h>
13 #include <asm/debug.h>
14
15 #include <linux/slab.h>
16 #include <linux/hdreg.h>        /* HDIO_GETGEO                      */
17 #include <linux/bio.h>
18 #include <linux/module.h>
19 #include <linux/init.h>
20
21 #include <asm/idals.h>
22 #include <asm/ebcdic.h>
23 #include <asm/io.h>
24 #include <asm/todclk.h>
25 #include <asm/ccwdev.h>
26
27 #include "dasd_int.h"
28 #include "dasd_fba.h"
29
30 #ifdef PRINTK_HEADER
31 #undef PRINTK_HEADER
32 #endif                          /* PRINTK_HEADER */
33 #define PRINTK_HEADER "dasd(fba):"
34
35 #define DASD_FBA_CCW_WRITE 0x41
36 #define DASD_FBA_CCW_READ 0x42
37 #define DASD_FBA_CCW_LOCATE 0x43
38 #define DASD_FBA_CCW_DEFINE_EXTENT 0x63
39
40 MODULE_LICENSE("GPL");
41
42 static struct dasd_discipline dasd_fba_discipline;
43
44 struct dasd_fba_private {
45         struct dasd_fba_characteristics rdc_data;
46 };
47
48 static struct ccw_device_id dasd_fba_ids[] = {
49         { CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), driver_info: 0x1},
50         { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), driver_info: 0x2},
51         { /* end of list */ },
52 };
53
54 MODULE_DEVICE_TABLE(ccw, dasd_fba_ids);
55
56 static struct ccw_driver dasd_fba_driver; /* see below */
57 static int
58 dasd_fba_probe(struct ccw_device *cdev)
59 {
60         int ret;
61
62         ret = dasd_generic_probe (cdev, &dasd_fba_discipline);
63         if (ret)
64                 return ret;
65         ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
66         return 0;
67 }
68
69 static int
70 dasd_fba_set_online(struct ccw_device *cdev)
71 {
72         return dasd_generic_set_online (cdev, &dasd_fba_discipline);
73 }
74
75 static struct ccw_driver dasd_fba_driver = {
76         .name        = "dasd-fba",
77         .owner       = THIS_MODULE,
78         .ids         = dasd_fba_ids,
79         .probe       = dasd_fba_probe,
80         .remove      = dasd_generic_remove,
81         .set_offline = dasd_generic_set_offline,
82         .set_online  = dasd_fba_set_online,
83         .notify      = dasd_generic_notify,
84 };
85
86 static inline void
87 define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
88               int blksize, int beg, int nr)
89 {
90         ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
91         ccw->flags = 0;
92         ccw->count = 16;
93         ccw->cda = (__u32) __pa(data);
94         memset(data, 0, sizeof (struct DE_fba_data));
95         if (rw == WRITE)
96                 (data->mask).perm = 0x0;
97         else if (rw == READ)
98                 (data->mask).perm = 0x1;
99         else
100                 data->mask.perm = 0x2;
101         data->blk_size = blksize;
102         data->ext_loc = beg;
103         data->ext_end = nr - 1;
104 }
105
106 static inline void
107 locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
108               int block_nr, int block_ct)
109 {
110         ccw->cmd_code = DASD_FBA_CCW_LOCATE;
111         ccw->flags = 0;
112         ccw->count = 8;
113         ccw->cda = (__u32) __pa(data);
114         memset(data, 0, sizeof (struct LO_fba_data));
115         if (rw == WRITE)
116                 data->operation.cmd = 0x5;
117         else if (rw == READ)
118                 data->operation.cmd = 0x6;
119         else
120                 data->operation.cmd = 0x8;
121         data->blk_nr = block_nr;
122         data->blk_ct = block_ct;
123 }
124
125 static int
126 dasd_fba_check_characteristics(struct dasd_device *device)
127 {
128         struct dasd_fba_private *private;
129         struct ccw_device *cdev = device->cdev; 
130         void *rdc_data;
131         int rc;
132
133         private = (struct dasd_fba_private *) device->private;
134         if (private == NULL) {
135                 private = kmalloc(sizeof(struct dasd_fba_private), GFP_KERNEL);
136                 if (private == NULL) {
137                         MESSAGE(KERN_WARNING, "%s",
138                                 "memory allocation failed for private data");
139                         return -ENOMEM;
140                 }
141                 device->private = (void *) private;
142         }
143         /* Read Device Characteristics */
144         rdc_data = (void *) &(private->rdc_data);
145         rc = read_dev_chars(device->cdev, &rdc_data, 32);
146         if (rc) {
147                 MESSAGE(KERN_WARNING,
148                         "Read device characteristics returned error %d", rc);
149                 return rc;
150         }
151
152         DEV_MESSAGE(KERN_INFO, device,
153                     "%04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)",
154                     cdev->id.dev_type,
155                     cdev->id.dev_model,
156                     cdev->id.cu_type,
157                     cdev->id.cu_model,
158                     ((private->rdc_data.blk_bdsa *
159                       (private->rdc_data.blk_size >> 9)) >> 11),
160                     private->rdc_data.blk_size);
161         return 0;
162 }
163
164 static int
165 dasd_fba_do_analysis(struct dasd_device *device)
166 {
167         struct dasd_fba_private *private;
168         int sb, rc;
169
170         private = (struct dasd_fba_private *) device->private;
171         rc = dasd_check_blocksize(private->rdc_data.blk_size);
172         if (rc) {
173                 DEV_MESSAGE(KERN_INFO, device, "unknown blocksize %d",
174                             private->rdc_data.blk_size);
175                 return rc;
176         }
177         device->blocks = private->rdc_data.blk_bdsa;
178         device->bp_block = private->rdc_data.blk_size;
179         device->s2b_shift = 0;  /* bits to shift 512 to get a block */
180         for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1)
181                 device->s2b_shift++;
182         return 0;
183 }
184
185 static int
186 dasd_fba_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
187 {
188         if (dasd_check_blocksize(device->bp_block) != 0)
189                 return -EINVAL;
190         geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
191         geo->heads = 16;
192         geo->sectors = 128 >> device->s2b_shift;
193         return 0;
194 }
195
196 static dasd_era_t
197 dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
198 {
199         struct dasd_device *device;
200         struct ccw_device *cdev;
201
202         device = (struct dasd_device *) cqr->device;
203         if (irb->scsw.cstat == 0x00 &&
204             irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
205                 return dasd_era_none;
206         
207         cdev = device->cdev;
208         switch (cdev->id.dev_type) {
209         case 0x3370:
210                 return dasd_3370_erp_examine(cqr, irb);
211         case 0x9336:
212                 return dasd_9336_erp_examine(cqr, irb);
213         default:
214                 return dasd_era_recover;
215         }
216 }
217
218 static dasd_erp_fn_t
219 dasd_fba_erp_action(struct dasd_ccw_req * cqr)
220 {
221         return dasd_default_erp_action;
222 }
223
224 static dasd_erp_fn_t
225 dasd_fba_erp_postaction(struct dasd_ccw_req * cqr)
226 {
227         if (cqr->function == dasd_default_erp_action)
228                 return dasd_default_erp_postaction;
229
230         MESSAGE(KERN_WARNING, "unknown ERP action %p", cqr->function);
231
232         return NULL;
233 }
234
235 static struct dasd_ccw_req *
236 dasd_fba_build_cp(struct dasd_device * device, struct request *req)
237 {
238         struct dasd_fba_private *private;
239         unsigned long *idaws;
240         struct LO_fba_data *LO_data;
241         struct dasd_ccw_req *cqr;
242         struct ccw1 *ccw;
243         struct bio *bio;
244         struct bio_vec *bv;
245         char *dst;
246         int count, cidaw, cplength, datasize;
247         sector_t recid, first_rec, last_rec;
248         unsigned int blksize, off;
249         unsigned char cmd;
250         int i;
251
252         private = (struct dasd_fba_private *) device->private;
253         if (rq_data_dir(req) == READ) {
254                 cmd = DASD_FBA_CCW_READ;
255         } else if (rq_data_dir(req) == WRITE) {
256                 cmd = DASD_FBA_CCW_WRITE;
257         } else
258                 return ERR_PTR(-EINVAL);
259         blksize = device->bp_block;
260         /* Calculate record id of first and last block. */
261         first_rec = req->sector >> device->s2b_shift;
262         last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
263         /* Check struct bio and count the number of blocks for the request. */
264         count = 0;
265         cidaw = 0;
266         rq_for_each_bio(bio, req) {
267                 bio_for_each_segment(bv, bio, i) {
268                         if (bv->bv_len & (blksize - 1))
269                                 /* Fba can only do full blocks. */
270                                 return ERR_PTR(-EINVAL);
271                         count += bv->bv_len >> (device->s2b_shift + 9);
272 #if defined(CONFIG_ARCH_S390X)
273                         if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
274                                 cidaw += bv->bv_len / blksize;
275 #endif
276                 }
277         }
278         /* Paranoia. */
279         if (count != last_rec - first_rec + 1)
280                 return ERR_PTR(-EINVAL);
281         /* 1x define extent + 1x locate record + number of blocks */
282         cplength = 2 + count;
283         /* 1x define extent + 1x locate record */
284         datasize = sizeof(struct DE_fba_data) + sizeof(struct LO_fba_data) +
285                 cidaw * sizeof(unsigned long);
286         /*
287          * Find out number of additional locate record ccws if the device
288          * can't do data chaining.
289          */
290         if (private->rdc_data.mode.bits.data_chain == 0) {
291                 cplength += count - 1;
292                 datasize += (count - 1)*sizeof(struct LO_fba_data);
293         }
294         /* Allocate the ccw request. */
295         cqr = dasd_smalloc_request(dasd_fba_discipline.name,
296                                    cplength, datasize, device);
297         if (IS_ERR(cqr))
298                 return cqr;
299         ccw = cqr->cpaddr;
300         /* First ccw is define extent. */
301         define_extent(ccw++, cqr->data, rq_data_dir(req),
302                       device->bp_block, req->sector, req->nr_sectors);
303         /* Build locate_record + read/write ccws. */
304         idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data));
305         LO_data = (struct LO_fba_data *) (idaws + cidaw);
306         /* Locate record for all blocks for smart devices. */
307         if (private->rdc_data.mode.bits.data_chain != 0) {
308                 ccw[-1].flags |= CCW_FLAG_CC;
309                 locate_record(ccw++, LO_data++, rq_data_dir(req), 0, count);
310         }
311         recid = first_rec;
312         rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
313                 dst = page_address(bv->bv_page) + bv->bv_offset;
314                 if (dasd_page_cache) {
315                         char *copy = kmem_cache_alloc(dasd_page_cache,
316                                                       SLAB_DMA | __GFP_NOWARN);
317                         if (copy && rq_data_dir(req) == WRITE)
318                                 memcpy(copy + bv->bv_offset, dst, bv->bv_len);
319                         if (copy)
320                                 dst = copy + bv->bv_offset;
321                 }
322                 for (off = 0; off < bv->bv_len; off += blksize) {
323                         /* Locate record for stupid devices. */
324                         if (private->rdc_data.mode.bits.data_chain == 0) {
325                                 ccw[-1].flags |= CCW_FLAG_CC;
326                                 locate_record(ccw, LO_data++,
327                                               rq_data_dir(req),
328                                               recid - first_rec, 1);
329                                 ccw->flags = CCW_FLAG_CC;
330                                 ccw++;
331                         } else {
332                                 if (recid > first_rec)
333                                         ccw[-1].flags |= CCW_FLAG_DC;
334                                 else
335                                         ccw[-1].flags |= CCW_FLAG_CC;
336                         }
337                         ccw->cmd_code = cmd;
338                         ccw->count = device->bp_block;
339                         if (idal_is_needed(dst, blksize)) {
340                                 ccw->cda = (__u32)(addr_t) idaws;
341                                 ccw->flags = CCW_FLAG_IDA;
342                                 idaws = idal_create_words(idaws, dst, blksize);
343                         } else {
344                                 ccw->cda = (__u32)(addr_t) dst;
345                                 ccw->flags = 0;
346                         }
347                         ccw++;
348                         dst += blksize;
349                         recid++;
350                 }
351         }
352         cqr->device = device;
353         cqr->expires = 5 * 60 * HZ;     /* 5 minutes */
354         cqr->status = DASD_CQR_FILLED;
355         return cqr;
356 }
357
358 static int
359 dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
360 {
361         struct dasd_fba_private *private;
362         struct ccw1 *ccw;
363         struct bio *bio;
364         struct bio_vec *bv;
365         char *dst, *cda;
366         unsigned int blksize, off;
367         int i, status;
368
369         if (!dasd_page_cache)
370                 goto out;
371         private = (struct dasd_fba_private *) cqr->device->private;
372         blksize = cqr->device->bp_block;
373         ccw = cqr->cpaddr;
374         /* Skip over define extent & locate record. */
375         ccw++;
376         if (private->rdc_data.mode.bits.data_chain != 0)
377                 ccw++;
378         rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
379                 dst = page_address(bv->bv_page) + bv->bv_offset;
380                 for (off = 0; off < bv->bv_len; off += blksize) {
381                         /* Skip locate record. */
382                         if (private->rdc_data.mode.bits.data_chain == 0)
383                                 ccw++;
384                         if (dst) {
385                                 if (ccw->flags & CCW_FLAG_IDA)
386                                         cda = *((char **)((addr_t) ccw->cda));
387                                 else
388                                         cda = (char *)((addr_t) ccw->cda);
389                                 if (dst != cda) {
390                                         if (rq_data_dir(req) == READ)
391                                                 memcpy(dst, cda, bv->bv_len);
392                                         kmem_cache_free(dasd_page_cache,
393                                             (void *)((addr_t)cda & PAGE_MASK));
394                                 }
395                                 dst = NULL;
396                         }
397                         ccw++;
398                 }
399         }
400 out:
401         status = cqr->status == DASD_CQR_DONE;
402         dasd_sfree_request(cqr, cqr->device);
403         return status;
404 }
405
406 static int
407 dasd_fba_fill_info(struct dasd_device * device,
408                    struct dasd_information2_t * info)
409 {
410         info->label_block = 1;
411         info->FBA_layout = 1;
412         info->format = DASD_FORMAT_LDL;
413         info->characteristics_size = sizeof(struct dasd_fba_characteristics);
414         memcpy(info->characteristics,
415                &((struct dasd_fba_private *) device->private)->rdc_data,
416                sizeof (struct dasd_fba_characteristics));
417         info->confdata_size = 0;
418         return 0;
419 }
420
421 static void
422 dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
423                     struct irb *irb)
424 {
425         char *page;
426
427         page = (char *) get_zeroed_page(GFP_KERNEL);
428         if (page == NULL) {
429                 MESSAGE(KERN_ERR, "%s", "No memory to dump sense data");
430                 return;
431         }
432         sprintf(page, KERN_WARNING PRINTK_HEADER
433                 "device %s: I/O status report:\n",
434                 device->cdev->dev.bus_id);
435
436         MESSAGE(KERN_ERR, "Sense data:\n%s", page);
437
438         free_page((unsigned long) page);
439 }
440
441 /*
442  * max_blocks is dependent on the amount of storage that is available
443  * in the static io buffer for each device. Currently each device has
444  * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
445  * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use
446  * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
447  * addition we have one define extent ccw + 16 bytes of data and a 
448  * locate record ccw for each block (stupid devices!) + 16 bytes of data.
449  * That makes:
450  * (8192 - 24 - 136 - 8 - 16) / 40 = 200.2 blocks at maximum.
451  * We want to fit two into the available memory so that we can immediately
452  * start the next request if one finishes off. That makes 100.1 blocks
453  * for one request. Give a little safety and the result is 96.
454  */
455 static struct dasd_discipline dasd_fba_discipline = {
456         .owner = THIS_MODULE,
457         .name = "FBA ",
458         .ebcname = "FBA ",
459         .max_blocks = 96,
460         .check_device = dasd_fba_check_characteristics,
461         .do_analysis = dasd_fba_do_analysis,
462         .fill_geometry = dasd_fba_fill_geometry,
463         .start_IO = dasd_start_IO,
464         .term_IO = dasd_term_IO,
465         .examine_error = dasd_fba_examine_error,
466         .erp_action = dasd_fba_erp_action,
467         .erp_postaction = dasd_fba_erp_postaction,
468         .build_cp = dasd_fba_build_cp,
469         .free_cp = dasd_fba_free_cp,
470         .dump_sense = dasd_fba_dump_sense,
471         .fill_info = dasd_fba_fill_info,
472 };
473
474 static int __init
475 dasd_fba_init(void)
476 {
477         int ret;
478
479         ASCEBC(dasd_fba_discipline.ebcname, 4);
480
481         ret = ccw_driver_register(&dasd_fba_driver);
482         if (ret)
483                 return ret;
484
485         dasd_generic_auto_online(&dasd_fba_driver);
486         return 0;
487 }
488
489 static void __exit
490 dasd_fba_cleanup(void)
491 {
492         ccw_driver_unregister(&dasd_fba_driver);
493 }
494
495 module_init(dasd_fba_init);
496 module_exit(dasd_fba_cleanup);
497
498 /*
499  * Overrides for Emacs so that we follow Linus's tabbing style.
500  * Emacs will notice this stuff at the end of the file and automatically
501  * adjust the settings for this buffer only.  This must remain at the end
502  * of the file.
503  * ---------------------------------------------------------------------------
504  * Local variables:
505  * c-indent-level: 4 
506  * c-brace-imaginary-offset: 0
507  * c-brace-offset: -4
508  * c-argdecl-indent: 4
509  * c-label-offset: -4
510  * c-continued-statement-offset: 4
511  * c-continued-brace-offset: 0
512  * indent-tabs-mode: 1
513  * tab-width: 8
514  * End:
515  */