ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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.33 $
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                         cidaw += idal_nr_words(page_address(bv->bv_page) +
274                                                bv->bv_offset, bv->bv_len);
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                 for (off = 0; off < bv->bv_len; off += blksize) {
315                         /* Locate record for stupid devices. */
316                         if (private->rdc_data.mode.bits.data_chain == 0) {
317                                 ccw[-1].flags |= CCW_FLAG_CC;
318                                 locate_record(ccw, LO_data++,
319                                               rq_data_dir(req),
320                                               recid - first_rec, 1);
321                                 ccw->flags = CCW_FLAG_CC;
322                                 ccw++;
323                         } else {
324                                 if (recid > first_rec)
325                                         ccw[-1].flags |= CCW_FLAG_DC;
326                                 else
327                                         ccw[-1].flags |= CCW_FLAG_CC;
328                         }
329                         ccw->cmd_code = cmd;
330                         ccw->count = device->bp_block;
331                         if (idal_is_needed(dst, blksize)) {
332                                 ccw->cda = (__u32)(addr_t) idaws;
333                                 ccw->flags = CCW_FLAG_IDA;
334                                 idaws = idal_create_words(idaws, dst, blksize);
335                         } else {
336                                 ccw->cda = (__u32)(addr_t) dst;
337                                 ccw->flags = 0;
338                         }
339                         ccw++;
340                         dst += blksize;
341                         recid++;
342                 }
343         }
344         cqr->device = device;
345         cqr->expires = 5 * 60 * HZ;     /* 5 minutes */
346         cqr->status = DASD_CQR_FILLED;
347         return cqr;
348 }
349
350 static int
351 dasd_fba_fill_info(struct dasd_device * device,
352                    struct dasd_information2_t * info)
353 {
354         info->label_block = 1;
355         info->FBA_layout = 1;
356         info->format = DASD_FORMAT_LDL;
357         info->characteristics_size = sizeof(struct dasd_fba_characteristics);
358         memcpy(info->characteristics,
359                &((struct dasd_fba_private *) device->private)->rdc_data,
360                sizeof (struct dasd_fba_characteristics));
361         info->confdata_size = 0;
362         return 0;
363 }
364
365 static void
366 dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
367                     struct irb *irb)
368 {
369         char *page;
370
371         page = (char *) get_zeroed_page(GFP_KERNEL);
372         if (page == NULL) {
373                 MESSAGE(KERN_ERR, "%s", "No memory to dump sense data");
374                 return;
375         }
376         sprintf(page, KERN_WARNING PRINTK_HEADER
377                 "device %s: I/O status report:\n",
378                 device->cdev->dev.bus_id);
379
380         MESSAGE(KERN_ERR, "Sense data:\n%s", page);
381
382         free_page((unsigned long) page);
383 }
384
385 /*
386  * max_blocks is dependent on the amount of storage that is available
387  * in the static io buffer for each device. Currently each device has
388  * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
389  * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use
390  * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
391  * addition we have one define extent ccw + 16 bytes of data and a 
392  * locate record ccw for each block (stupid devices!) + 16 bytes of data.
393  * That makes:
394  * (8192 - 24 - 136 - 8 - 16) / 40 = 200.2 blocks at maximum.
395  * We want to fit two into the available memory so that we can immediately
396  * start the next request if one finishes off. That makes 100.1 blocks
397  * for one request. Give a little safety and the result is 96.
398  */
399 static struct dasd_discipline dasd_fba_discipline = {
400         .owner = THIS_MODULE,
401         .name = "FBA ",
402         .ebcname = "FBA ",
403         .max_blocks = 96,
404         .check_device = dasd_fba_check_characteristics,
405         .do_analysis = dasd_fba_do_analysis,
406         .fill_geometry = dasd_fba_fill_geometry,
407         .start_IO = dasd_start_IO,
408         .term_IO = dasd_term_IO,
409         .examine_error = dasd_fba_examine_error,
410         .erp_action = dasd_fba_erp_action,
411         .erp_postaction = dasd_fba_erp_postaction,
412         .build_cp = dasd_fba_build_cp,
413         .dump_sense = dasd_fba_dump_sense,
414         .fill_info = dasd_fba_fill_info,
415 };
416
417 static int __init
418 dasd_fba_init(void)
419 {
420         int ret;
421
422         ASCEBC(dasd_fba_discipline.ebcname, 4);
423
424         ret = ccw_driver_register(&dasd_fba_driver);
425         if (ret)
426                 return ret;
427
428         dasd_generic_auto_online(&dasd_fba_driver);
429         return 0;
430 }
431
432 static void __exit
433 dasd_fba_cleanup(void)
434 {
435         ccw_driver_unregister(&dasd_fba_driver);
436 }
437
438 module_init(dasd_fba_init);
439 module_exit(dasd_fba_cleanup);
440
441 /*
442  * Overrides for Emacs so that we follow Linus's tabbing style.
443  * Emacs will notice this stuff at the end of the file and automatically
444  * adjust the settings for this buffer only.  This must remain at the end
445  * of the file.
446  * ---------------------------------------------------------------------------
447  * Local variables:
448  * c-indent-level: 4 
449  * c-brace-imaginary-offset: 0
450  * c-brace-offset: -4
451  * c-argdecl-indent: 4
452  * c-label-offset: -4
453  * c-continued-statement-offset: 4
454  * c-continued-brace-offset: 0
455  * indent-tabs-mode: 1
456  * tab-width: 8
457  * End:
458  */