dasd_diag.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:15k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* 
  2.  * File...........: linux/drivers/s390/block/dasd_diag.c
  3.  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  4.  * Based on.......: linux/drivers/s390/block/mdisk.c
  5.  * ...............: by Hartmunt Penner <hpenner@de.ibm.com>
  6.  * Bugreports.to..: <Linux390@de.ibm.com>
  7.  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  8.  * History of changes
  9.  * 07/13/00 Added fixup sections for diagnoses ans saved some registers
  10.  * 07/14/00 fixed constraints in newly generated inline asm
  11.  * 10/05/00 adapted to 'new' DASD driver
  12.  *          fixed return codes of dia250()
  13.  *          fixed partition handling and HDIO_GETGEO
  14.  */
  15. #include <linux/config.h>
  16. #include <linux/stddef.h>
  17. #include <linux/kernel.h>
  18. #include <asm/debug.h>
  19. #include <linux/slab.h>
  20. #include <linux/hdreg.h> /* HDIO_GETGEO                      */
  21. #include <linux/blk.h>
  22. #include <asm/ccwcache.h>
  23. #include <asm/dasd.h>
  24. #include <asm/ebcdic.h>
  25. #include <asm/io.h>
  26. #include <asm/irq.h>
  27. #include <asm/s390dyn.h>
  28. #include "dasd_int.h"
  29. #include "dasd_diag.h"
  30. #ifdef PRINTK_HEADER
  31. #undef PRINTK_HEADER
  32. #endif /* PRINTK_HEADER */
  33. #define PRINTK_HEADER DASD_NAME"(diag):"
  34. dasd_discipline_t dasd_diag_discipline;
  35. typedef struct
  36.     dasd_diag_private_t {
  37. dasd_diag_characteristics_t rdc_data;
  38. diag_rw_io_t iob;
  39. diag_init_io_t iib;
  40. unsigned long *label;
  41. } dasd_diag_private_t;
  42. static __inline__ int
  43. dia210 (void *devchar)
  44. {
  45. int rc;
  46. __asm__ __volatile__ ("    diag  %1,0,0x210n"
  47.       "0:  ipm   %0n"
  48.       "    srl   %0,28n"
  49.       "1:n"
  50.       ".section .fixup,"ax"n"
  51.       "2:  lhi   %0,3n"
  52.       "    bras  1,3fn"
  53.       "    .long 1bn"
  54.       "3:  l     1,0(1)n"
  55.       "    br    1n"
  56.       ".previousn"
  57.       ".section __ex_table,"a"n"
  58.       "    .align 4n"
  59.       "    .long 0b,2bn" ".previousn":"=d" (rc)
  60.       :"d" ((void *) __pa (devchar))
  61.       :"1");
  62. return rc;
  63. }
  64. static __inline__ int
  65. dia250 (void *iob, int cmd)
  66. {
  67. __asm__ __volatile__ ("    lr    0,%1n"
  68.       "    diag  0,%0,0x250n"
  69.       "0:  ipm   %0n"
  70.       "    srl   %0,28n"
  71.       "    or    %0,1n"
  72.       "1:n"
  73.       ".section .fixup,"ax"n"
  74.       "2:  lhi   %0,3n"
  75.       "    bras  1,3fn"
  76.       "    .long 1bn"
  77.       "3:  l     1,0(1)n"
  78.       "    br    1n"
  79.       ".previousn"
  80.       ".section __ex_table,"a"n"
  81.       "    .align 4n"
  82.       "    .long 0b,2bn" ".previousn":"+d" (cmd)
  83.       :"d" ((void *) __pa (iob))
  84.       :"0", "1", "cc");
  85. return cmd;
  86. }
  87. static __inline__ int
  88. mdsk_init_io (dasd_device_t * device, int blocksize, int offset, int size)
  89. {
  90. dasd_diag_private_t *private = (dasd_diag_private_t *) device->private;
  91. diag_init_io_t *iib = &private->iib;
  92. int rc;
  93. memset (iib, 0, sizeof (diag_init_io_t));
  94. iib->dev_nr = device->devinfo.devno;
  95. iib->block_size = blocksize;
  96. iib->offset = offset;
  97. iib->start_block = 0;
  98. iib->end_block = size;
  99. rc = dia250 (iib, INIT_BIO);
  100. return rc & 3;
  101. }
  102. static __inline__ int
  103. mdsk_term_io (dasd_device_t * device)
  104. {
  105. dasd_diag_private_t *private = (dasd_diag_private_t *) device->private;
  106. diag_init_io_t *iib = &private->iib;
  107. int rc;
  108. memset (iib, 0, sizeof (diag_init_io_t));
  109. iib->dev_nr = device->devinfo.devno;
  110. rc = dia250 (iib, TERM_BIO);
  111. return rc & 3;
  112. }
  113. int
  114. dasd_start_diag (ccw_req_t * cqr)
  115. {
  116. int rc;
  117. dasd_device_t *device = cqr->device;
  118. dasd_diag_private_t *private;
  119. diag_rw_io_t *iob;
  120. private = (dasd_diag_private_t *) device->private;
  121. iob = &private->iob;
  122. iob->dev_nr = device->devinfo.devno;
  123. iob->key = 0;
  124. iob->flags = 2;
  125. iob->block_count = cqr->cplength >> 1;
  126. iob->interrupt_params = (u32) cqr;
  127. iob->bio_list = __pa (cqr->cpaddr);
  128. asm volatile ("STCK %0":"=m" (cqr->startclk));
  129. rc = dia250 (iob, RW_BIO);
  130. if (rc > 8) {
  131. PRINT_WARN ("dia250 returned CC %dn", rc);
  132. check_then_set (&cqr->status,
  133. CQR_STATUS_QUEUED, CQR_STATUS_ERROR);
  134. } else if (rc == 0) {
  135. check_then_set (&cqr->status,
  136. CQR_STATUS_QUEUED, CQR_STATUS_DONE);
  137. dasd_schedule_bh (device);
  138. } else {
  139. check_then_set (&cqr->status,
  140. CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
  141. rc = 0;
  142. }
  143. return rc;
  144. }
  145. void
  146. dasd_ext_handler (struct pt_regs *regs, __u16 code)
  147. {
  148.      int cpu = smp_processor_id();
  149. ccw_req_t *cqr;
  150. int ip = S390_lowcore.ext_params;
  151. char status = *((char *) &S390_lowcore.ext_params + 5);
  152. dasd_device_t *device;
  153. int done_fast_io = 0;
  154. int devno;
  155.         unsigned long flags;
  156. irq_enter(cpu, -1);
  157. if (!ip) { /* no intparm: unsolicited interrupt */
  158. printk (KERN_WARNING PRINTK_HEADER
  159. "caught unsolicited interruptn");
  160. irq_exit(cpu, -1);
  161. return;
  162. }
  163. if (ip & 0x80000001) {
  164. printk (KERN_WARNING PRINTK_HEADER
  165. "caught spurious interrupt with parm %08xn", ip);
  166. irq_exit(cpu, -1);
  167. return;
  168. }
  169. cqr = (ccw_req_t *) ip;
  170. device = (dasd_device_t *) cqr->device;
  171. devno = device->devinfo.devno;
  172. if (device == NULL) {
  173. printk (KERN_WARNING PRINTK_HEADER
  174. " INT on devno 0x%04X  = /dev/%s (%d:%d)"
  175. " belongs to NULL devicen",
  176. devno, device->name, MAJOR (device->kdev),
  177. MINOR (device->kdev));
  178. }
  179. if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
  180. printk (KERN_WARNING PRINTK_HEADER
  181. "0x%04X : /dev/%s (%d:%d)"
  182. " magic number of ccw_req_t 0x%08X doesn't match"
  183. " discipline 0x%08Xn",
  184. devno, device->name,
  185. MAJOR (device->kdev), MINOR (device->kdev),
  186. cqr->magic, *(int *) (&device->discipline->name));
  187. irq_exit(cpu, -1);
  188. return;
  189. }
  190.         /* get irq lock to modify request queue */
  191.         s390irq_spin_lock_irqsave (device->devinfo.irq, 
  192.                                    flags);
  193. asm volatile ("STCK %0":"=m" (cqr->stopclk));
  194. switch (status) {
  195. case 0x00:
  196. check_then_set (&cqr->status,
  197. CQR_STATUS_IN_IO, CQR_STATUS_DONE);
  198. if (cqr->next && (cqr->next->status == CQR_STATUS_QUEUED)) {
  199. if (dasd_start_diag (cqr->next) == 0) {
  200. done_fast_io = 1;
  201. }
  202. }
  203. break;
  204. case 0x01:
  205. case 0x02:
  206. case 0x03:
  207. default:
  208. check_then_set (&cqr->status,
  209. CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
  210. break;
  211. }
  212.         s390irq_spin_unlock_irqrestore (device->devinfo.irq, 
  213.                                         flags);
  214. wake_up (&device->wait_q);
  215. dasd_schedule_bh (device);
  216. irq_exit(cpu, -1);
  217. }
  218. static int
  219. dasd_diag_check_characteristics (struct dasd_device_t *device)
  220. {
  221. int rc = 0;
  222. int bsize;
  223. int label_block;
  224. dasd_diag_private_t *private;
  225. dasd_diag_characteristics_t *rdc_data;
  226. ccw_req_t *cqr;
  227. long *label;
  228. int sb;
  229. if (device == NULL) {
  230. printk (KERN_WARNING PRINTK_HEADER
  231. "Null device pointer passed to characteristics checkern");
  232. return -ENODEV;
  233. }
  234. device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL);
  235. if (device->private == NULL) {
  236. printk (KERN_WARNING PRINTK_HEADER
  237. "memory allocation failed for private datan");
  238. rc = -ENOMEM;
  239.                 goto fail;
  240. }
  241. private = (dasd_diag_private_t *) device->private;
  242. rdc_data = (void *) &(private->rdc_data);
  243. rdc_data->dev_nr = device->devinfo.devno;
  244. rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t);
  245.         rc = dia210 (rdc_data);
  246. if ( rc != 0) {
  247. goto fail;
  248. }
  249. if (rdc_data->vdev_class != DEV_CLASS_FBA &&
  250.     rdc_data->vdev_class != DEV_CLASS_ECKD &&
  251.     rdc_data->vdev_class != DEV_CLASS_CKD) {
  252.                 rc = -ENOTSUPP;
  253. goto fail;
  254. }
  255. #if 0
  256. printk (KERN_INFO PRINTK_HEADER
  257. "%04X: %04X on real %04X/%02Xn",
  258. rdc_data->dev_nr,
  259. rdc_data->vdev_type, rdc_data->rdev_type, rdc_data->rdev_model);
  260. #endif
  261. /* Figure out position of label block */
  262. if (private->rdc_data.vdev_class == DEV_CLASS_FBA) {
  263. device->sizes.pt_block = 1;
  264. } else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD ||
  265.    private->rdc_data.vdev_class == DEV_CLASS_CKD) {
  266. device->sizes.pt_block = 2;
  267. } else {
  268.                 BUG();
  269. }
  270. private->label = (long *) get_free_page (GFP_KERNEL);
  271. label = private->label;
  272. mdsk_term_io (device); /* first terminate all outstanding operations */
  273. /* figure out blocksize of device */
  274. for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
  275. diag_bio_t *bio;
  276. diag_rw_io_t *iob = &private->iob;
  277. rc = mdsk_init_io (device, bsize, 0, 64);
  278. if (rc > 4) {
  279. continue;
  280. }
  281. cqr = dasd_alloc_request (dasd_diag_discipline.name,
  282.                                          sizeof (diag_bio_t) / sizeof (ccw1_t),
  283.                                          0, device);
  284. if (cqr == NULL) {
  285. printk (KERN_WARNING PRINTK_HEADER
  286. "No memory to allocate initialization requestn");
  287. free_page ((long) private->label);
  288.                         rc = -ENOMEM;
  289.                         goto fail;
  290. }
  291. bio = (diag_bio_t *) (cqr->cpaddr);
  292. memset (bio, 0, sizeof (diag_bio_t));
  293. bio->type = MDSK_READ_REQ;
  294. bio->block_number = device->sizes.pt_block + 1;
  295. bio->buffer = __pa (private->label);
  296. cqr->device = device;
  297. cqr->status = CQR_STATUS_FILLED;
  298. memset (iob, 0, sizeof (diag_rw_io_t));
  299. iob->dev_nr = rdc_data->dev_nr;
  300. iob->block_count = 1;
  301. iob->interrupt_params = (u32) cqr;
  302. iob->bio_list = __pa (bio);
  303. rc = dia250 (iob, RW_BIO);
  304. if (rc == 0) {
  305. if (label[3] != bsize ||
  306.                             label[0] != 0xc3d4e2f1 || /* != CMS1 */
  307.                             label[13] == 0 ){
  308.                                 rc = -EMEDIUMTYPE;
  309. goto fail;
  310. }
  311. break;
  312. }
  313. mdsk_term_io (device);
  314. }
  315.         if (bsize > PAGE_SIZE) {
  316.                 rc = -EMEDIUMTYPE;
  317. goto fail;
  318.         }
  319. device->sizes.blocks = label[7];
  320. device->sizes.bp_block = bsize;
  321. device->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */
  322. for (sb = 512; sb < bsize; sb = sb << 1)
  323. device->sizes.s2b_shift++;
  324. printk (KERN_INFO PRINTK_HEADER
  325. "/dev/%s (%04X): capacity (%dkB blks): %ldkBn",
  326. device->name, device->devinfo.devno,
  327. (device->sizes.bp_block >> 10),
  328. (device->sizes.blocks << device->sizes.s2b_shift) >> 1);
  329. free_page ((long) private->label);
  330.         rc = 0;
  331. goto out;
  332.  fail:
  333.         if ( rc ) {
  334.                 kfree (device->private);
  335.                 device->private = NULL;
  336.         }
  337.  out:
  338. return rc;
  339. }
  340. static int
  341. dasd_diag_fill_geometry (struct dasd_device_t *device, struct hd_geometry *geo)
  342. {
  343. int rc = 0;
  344. dasd_diag_private_t *private = (dasd_diag_private_t *) device->private;
  345. unsigned long sectors = device->sizes.blocks << device->sizes.s2b_shift;
  346. unsigned long tracks = sectors >> 6;
  347. unsigned long trk_rem = sectors & ((1 << 6) - 1); /* 64k per track */
  348. unsigned long cyls = tracks >> 4;
  349. unsigned long cyls_rem = tracks & ((1 << 4) - 1); /* 16 head per cyl */
  350. switch (device->sizes.bp_block) {
  351. case 512:
  352. case 1024:
  353. case 2048:
  354. case 4096:
  355. break;
  356. default:
  357. return -EINVAL;
  358. }
  359. geo->cylinders = cyls;
  360. geo->heads = 16;
  361. geo->sectors = 128 >> device->sizes.s2b_shift;
  362. return rc;
  363. }
  364. static dasd_era_t
  365. dasd_diag_examine_error (ccw_req_t * cqr, devstat_t * stat)
  366. {
  367. return dasd_era_fatal;
  368. }
  369. static ccw_req_t *
  370. dasd_diag_build_cp_from_req (dasd_device_t * device, struct request *req)
  371. {
  372. ccw_req_t *rw_cp = NULL;
  373. struct buffer_head *bh;
  374. int rw_cmd;
  375. int noblk = req->nr_sectors >> device->sizes.s2b_shift;
  376. int byt_per_blk = device->sizes.bp_block;
  377. int block;
  378. diag_bio_t *bio;
  379. int bhct;
  380. long size;
  381. if (!noblk) {
  382. PRINT_ERR ("No blocks to read/write...returningn");
  383. return NULL;
  384. }
  385. if (req->cmd == READ) {
  386. rw_cmd = MDSK_READ_REQ;
  387. } else if (req->cmd == WRITE) {
  388. rw_cmd = MDSK_WRITE_REQ;
  389. }
  390. bhct = 0;
  391. for (bh = req->bh; bh; bh = bh->b_reqnext) {
  392. if (bh->b_size < byt_per_blk)
  393.                         BUG();
  394.                 bhct += bh->b_size >> (device->sizes.s2b_shift+9);
  395. }
  396. /* Build the request */
  397. rw_cp = dasd_alloc_request (dasd_diag_discipline.name, bhct << 1, 0, device);
  398. if (!rw_cp) {
  399. return NULL;
  400. }
  401. bio = (diag_bio_t *) (rw_cp->cpaddr);
  402. block = req->sector >> device->sizes.s2b_shift;
  403. for (bh = req->bh; bh; bh = bh->b_reqnext) {
  404.                 memset (bio, 0, sizeof (diag_bio_t));
  405.                 for (size = 0; size < bh->b_size; size += byt_per_blk) {
  406.                         bio->type = rw_cmd;
  407.                         bio->block_number = block + 1;
  408.                         bio->buffer = __pa (bh->b_data + size);
  409.                         bio++;
  410.                         block++;
  411.                 }
  412. }
  413. asm volatile ("STCK %0":"=m" (rw_cp->buildclk));
  414. rw_cp->device = device;
  415. rw_cp->expires = 50 * TOD_SEC; /* 50 seconds */
  416. rw_cp->req = req;
  417. check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
  418. return rw_cp;
  419. }
  420. static int
  421. dasd_diag_fill_info (dasd_device_t * device, dasd_information_t * info)
  422. {
  423. int rc = 0;
  424. info->FBA_layout = 1;
  425. info->characteristics_size = sizeof (dasd_diag_characteristics_t);
  426. memcpy (info->characteristics,
  427. &((dasd_diag_private_t *) device->private)->rdc_data,
  428. sizeof (dasd_diag_characteristics_t));
  429. info->confdata_size = 0;
  430. return rc;
  431. }
  432. static char *
  433. dasd_diag_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
  434. {
  435. char *page = (char *) get_free_page (GFP_KERNEL);
  436. int len;
  437. if (page == NULL) {
  438. return NULL;
  439. }
  440. len = sprintf (page, KERN_WARNING PRINTK_HEADER
  441.        "device %04X on irq %d: I/O status report:n",
  442.        device->devinfo.devno, device->devinfo.irq);
  443. return page;
  444. }
  445. dasd_discipline_t dasd_diag_discipline = {
  446.         owner: THIS_MODULE,
  447. name:"DIAG",
  448. ebcname:"DIAG",
  449. max_blocks:PAGE_SIZE / sizeof (diag_bio_t),
  450. check_characteristics:dasd_diag_check_characteristics,
  451. fill_geometry:dasd_diag_fill_geometry,
  452. start_IO:dasd_start_diag,
  453. examine_error:dasd_diag_examine_error,
  454. build_cp_from_req:dasd_diag_build_cp_from_req,
  455. dump_sense:dasd_diag_dump_sense,
  456. int_handler:dasd_ext_handler,
  457. fill_info:dasd_diag_fill_info,
  458. };
  459. int
  460. dasd_diag_init (void)
  461. {
  462. int rc = 0;
  463. if (MACHINE_IS_VM) {
  464. printk (KERN_INFO PRINTK_HEADER
  465. "%s discipline initializingn",
  466. dasd_diag_discipline.name);
  467. ASCEBC (dasd_diag_discipline.ebcname, 4);
  468. ctl_set_bit (0, 9);
  469. register_external_interrupt (0x2603, dasd_ext_handler);
  470. dasd_discipline_add (&dasd_diag_discipline);
  471. } else {
  472. printk (KERN_INFO PRINTK_HEADER
  473. "Machine is not VM: %s discipline not initializingn",
  474. dasd_diag_discipline.name);
  475. rc = -EINVAL;
  476. }
  477. return rc;
  478. }
  479. void
  480. dasd_diag_cleanup (void)
  481. {
  482. if (MACHINE_IS_VM) {
  483. printk (KERN_INFO PRINTK_HEADER
  484. "%s discipline cleaning upn",
  485. dasd_diag_discipline.name);
  486. dasd_discipline_del (&dasd_diag_discipline);
  487. unregister_external_interrupt (0x2603, dasd_ext_handler);
  488. ctl_clear_bit (0, 9);
  489. } else {
  490. printk (KERN_INFO PRINTK_HEADER
  491. "Machine is not VM: %s discipline not initializingn",
  492. dasd_diag_discipline.name);
  493. }
  494. }
  495. #ifdef MODULE
  496. int
  497. init_module (void)
  498. {
  499. int rc = 0;
  500. rc = dasd_diag_init ();
  501. return rc;
  502. }
  503. void
  504. cleanup_module (void)
  505. {
  506. dasd_diag_cleanup ();
  507. return;
  508. }
  509. #endif
  510. /*
  511.  * Overrides for Emacs so that we follow Linus's tabbing style.
  512.  * Emacs will notice this stuff at the end of the file and automatically
  513.  * adjust the settings for this buffer only.  This must remain at the end
  514.  * of the file.
  515.  * ---------------------------------------------------------------------------
  516.  * Local variables:
  517.  * c-indent-level: 4 
  518.  * c-brace-imaginary-offset: 0
  519.  * c-brace-offset: -4
  520.  * c-argdecl-indent: 4
  521.  * c-label-offset: -4
  522.  * c-continued-statement-offset: 4
  523.  * c-continued-brace-offset: 0
  524.  * indent-tabs-mode: nil
  525.  * tab-width: 8
  526.  * End:
  527.  */