scsicam.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:7k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * scsicam.c - SCSI CAM support functions, use for HDIO_GETGEO, etc.
  3.  *
  4.  * Copyright 1993, 1994 Drew Eckhardt
  5.  *      Visionary Computing 
  6.  *      (Unix and Linux consulting and custom programming)
  7.  *      drew@Colorado.EDU
  8.  *      +1 (303) 786-7975
  9.  *
  10.  * For more information, please consult the SCSI-CAM draft.
  11.  */
  12. #define __NO_VERSION__
  13. #include <linux/module.h>
  14. #include <linux/fs.h>
  15. #include <linux/genhd.h>
  16. #include <linux/kernel.h>
  17. #include <linux/blk.h>
  18. #include <asm/unaligned.h>
  19. #include "scsi.h"
  20. #include "hosts.h"
  21. #include "sd.h"
  22. #include <scsi/scsicam.h>
  23. static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
  24.    unsigned int *secs);
  25. /*
  26.  * Function : int scsicam_bios_param (Disk *disk, int dev, int *ip)
  27.  *
  28.  * Purpose : to determine the BIOS mapping used for a drive in a 
  29.  *      SCSI-CAM system, storing the results in ip as required
  30.  *      by the HDIO_GETGEO ioctl().
  31.  *
  32.  * Returns : -1 on failure, 0 on success.
  33.  *
  34.  */
  35. int scsicam_bios_param(Disk * disk, /* SCSI disk */
  36.        kdev_t dev, /* Device major, minor */
  37.   int *ip /* Heads, sectors, cylinders in that order */ )
  38. {
  39. struct buffer_head *bh;
  40. int ret_code;
  41. int size = disk->capacity;
  42. unsigned long temp_cyl;
  43. if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev))))
  44. return -1;
  45. /* try to infer mapping from partition table */
  46. ret_code = scsi_partsize(bh, (unsigned long) size, (unsigned int *) ip + 2,
  47.        (unsigned int *) ip + 0, (unsigned int *) ip + 1);
  48. brelse(bh);
  49. if (ret_code == -1) {
  50. /* pick some standard mapping with at most 1024 cylinders,
  51.    and at most 62 sectors per track - this works up to
  52.    7905 MB */
  53. ret_code = setsize((unsigned long) size, (unsigned int *) ip + 2,
  54.        (unsigned int *) ip + 0, (unsigned int *) ip + 1);
  55. }
  56. /* if something went wrong, then apparently we have to return
  57.    a geometry with more than 1024 cylinders */
  58. if (ret_code || ip[0] > 255 || ip[1] > 63) {
  59. ip[0] = 64;
  60. ip[1] = 32;
  61. temp_cyl = size / (ip[0] * ip[1]);
  62. if (temp_cyl > 65534) {
  63. ip[0] = 255;
  64. ip[1] = 63;
  65. }
  66. ip[2] = size / (ip[0] * ip[1]);
  67. }
  68. return 0;
  69. }
  70. /*
  71.  * Function : static int scsi_partsize(struct buffer_head *bh, unsigned long 
  72.  *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
  73.  *
  74.  * Purpose : to determine the BIOS mapping used to create the partition
  75.  *      table, storing the results in *cyls, *hds, and *secs 
  76.  *
  77.  * Returns : -1 on failure, 0 on success.
  78.  *
  79.  */
  80. int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
  81.        unsigned int *cyls, unsigned int *hds, unsigned int *secs)
  82. {
  83. struct partition *p, *largest = NULL;
  84. int i, largest_cyl;
  85. int cyl, ext_cyl, end_head, end_cyl, end_sector;
  86. unsigned int logical_end, physical_end, ext_physical_end;
  87. if (*(unsigned short *) (bh->b_data + 510) == 0xAA55) {
  88. for (largest_cyl = -1, p = (struct partition *)
  89.      (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) {
  90. if (!p->sys_ind)
  91. continue;
  92. #ifdef DEBUG
  93. printk("scsicam_bios_param : partition %d has system n",
  94.        i);
  95. #endif
  96. cyl = p->cyl + ((p->sector & 0xc0) << 2);
  97. if (cyl > largest_cyl) {
  98. largest_cyl = cyl;
  99. largest = p;
  100. }
  101. }
  102. }
  103. if (largest) {
  104. end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
  105. end_head = largest->end_head;
  106. end_sector = largest->end_sector & 0x3f;
  107. if (end_head + 1 == 0 || end_sector == 0)
  108. return -1;
  109. #ifdef DEBUG
  110. printk("scsicam_bios_param : end at h = %d, c = %d, s = %dn",
  111.        end_head, end_cyl, end_sector);
  112. #endif
  113. physical_end = end_cyl * (end_head + 1) * end_sector +
  114.     end_head * end_sector + end_sector;
  115. /* This is the actual _sector_ number at the end */
  116. logical_end = get_unaligned(&largest->start_sect)
  117.     + get_unaligned(&largest->nr_sects);
  118. /* This is for >1023 cylinders */
  119. ext_cyl = (logical_end - (end_head * end_sector + end_sector))
  120.     / (end_head + 1) / end_sector;
  121. ext_physical_end = ext_cyl * (end_head + 1) * end_sector +
  122.     end_head * end_sector + end_sector;
  123. #ifdef DEBUG
  124. printk("scsicam_bios_param : logical_end=%d physical_end=%d ext_physical_end=%d ext_cyl=%dn"
  125.   ,logical_end, physical_end, ext_physical_end, ext_cyl);
  126. #endif
  127. if ((logical_end == physical_end) ||
  128.   (end_cyl == 1023 && ext_physical_end == logical_end)) {
  129. *secs = end_sector;
  130. *hds = end_head + 1;
  131. *cyls = capacity / ((end_head + 1) * end_sector);
  132. return 0;
  133. }
  134. #ifdef DEBUG
  135. printk("scsicam_bios_param : logical (%u) != physical (%u)n",
  136.        logical_end, physical_end);
  137. #endif
  138. }
  139. return -1;
  140. }
  141. /*
  142.  * Function : static int setsize(unsigned long capacity,unsigned int *cyls,
  143.  *      unsigned int *hds, unsigned int *secs);
  144.  *
  145.  * Purpose : to determine a near-optimal int 0x13 mapping for a
  146.  *      SCSI disk in terms of lost space of size capacity, storing
  147.  *      the results in *cyls, *hds, and *secs.
  148.  *
  149.  * Returns : -1 on failure, 0 on success.
  150.  *
  151.  * Extracted from
  152.  *
  153.  * WORKING                                                    X3T9.2
  154.  * DRAFT                                                        792D
  155.  *
  156.  *
  157.  *                                                        Revision 6
  158.  *                                                         10-MAR-94
  159.  * Information technology -
  160.  * SCSI-2 Common access method
  161.  * transport and SCSI interface module
  162.  * 
  163.  * ANNEX A :
  164.  *
  165.  * setsize() converts a read capacity value to int 13h
  166.  * head-cylinder-sector requirements. It minimizes the value for
  167.  * number of heads and maximizes the number of cylinders. This
  168.  * will support rather large disks before the number of heads
  169.  * will not fit in 4 bits (or 6 bits). This algorithm also
  170.  * minimizes the number of sectors that will be unused at the end
  171.  * of the disk while allowing for very large disks to be
  172.  * accommodated. This algorithm does not use physical geometry. 
  173.  */
  174. static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
  175.    unsigned int *secs)
  176. {
  177. unsigned int rv = 0;
  178. unsigned long heads, sectors, cylinders, temp;
  179. cylinders = 1024L; /* Set number of cylinders to max */
  180. sectors = 62L; /* Maximize sectors per track */
  181. temp = cylinders * sectors; /* Compute divisor for heads */
  182. heads = capacity / temp; /* Compute value for number of heads */
  183. if (capacity % temp) { /* If no remainder, done! */
  184. heads++; /* Else, increment number of heads */
  185. temp = cylinders * heads; /* Compute divisor for sectors */
  186. sectors = capacity / temp; /* Compute value for sectors per
  187.    track */
  188. if (capacity % temp) { /* If no remainder, done! */
  189. sectors++; /* Else, increment number of sectors */
  190. temp = heads * sectors; /* Compute divisor for cylinders */
  191. cylinders = capacity / temp; /* Compute number of cylinders */
  192. }
  193. }
  194. if (cylinders == 0)
  195. rv = (unsigned) -1; /* Give error if 0 cylinders */
  196. *cyls = (unsigned int) cylinders; /* Stuff return values */
  197. *secs = (unsigned int) sectors;
  198. *hds = (unsigned int) heads;
  199. return (rv);
  200. }