Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * scsicam.c - SCSI CAM support functions, use for HDIO_GETGEO, etc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright 1993, 1994 Drew Eckhardt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *      Visionary Computing 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *      (Unix and Linux consulting and custom programming)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *      drew@Colorado.EDU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *      +1 (303) 786-7975
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * For more information, please consult the SCSI-CAM draft.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/genhd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/blkdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/msdos_partition.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <scsi/scsicam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26)  * scsi_bios_ptable - Read PC partition table out of first sector of device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27)  * @dev: from this device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)  * Description: Reads the first sector from the device and returns %0x42 bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30)  *              starting at offset %0x1be.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31)  * Returns: partition table in kmalloc(GFP_KERNEL) memory, or NULL on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) unsigned char *scsi_bios_ptable(struct block_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	struct address_space *mapping = dev->bd_contains->bd_inode->i_mapping;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 	unsigned char *res = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	struct page *page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	page = read_mapping_page(mapping, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	if (IS_ERR(page))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	if (!PageError(page))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 		res = kmemdup(page_address(page) + 0x1be, 66, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	put_page(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) EXPORT_SYMBOL(scsi_bios_ptable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51)  * scsi_partsize - Parse cylinders/heads/sectors from PC partition table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52)  * @bdev: block device to parse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53)  * @capacity: size of the disk in sectors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54)  * @geom: output in form of [hds, cylinders, sectors]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56)  * Determine the BIOS mapping/geometry used to create the partition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57)  * table, storing the results in @geom.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59)  * Returns: %false on failure, %true on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) bool scsi_partsize(struct block_device *bdev, sector_t capacity, int geom[3])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	int cyl, ext_cyl, end_head, end_cyl, end_sector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	unsigned int logical_end, physical_end, ext_physical_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	struct msdos_partition *p, *largest = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	void *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	int ret = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	buf = scsi_bios_ptable(bdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	if (*(unsigned short *) (buf + 64) == 0xAA55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		int largest_cyl = -1, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		for (i = 0, p = buf; i < 4; i++, p++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 			if (!p->sys_ind)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 				continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 			printk("scsicam_bios_param : partition %d has system \n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 			       i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 			cyl = p->cyl + ((p->sector & 0xc0) << 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 			if (cyl > largest_cyl) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 				largest_cyl = cyl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 				largest = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	if (largest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 		end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 		end_head = largest->end_head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 		end_sector = largest->end_sector & 0x3f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		if (end_head + 1 == 0 || end_sector == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 			goto out_free_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		printk("scsicam_bios_param : end at h = %d, c = %d, s = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		       end_head, end_cyl, end_sector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		physical_end = end_cyl * (end_head + 1) * end_sector +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		    end_head * end_sector + end_sector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		/* This is the actual _sector_ number at the end */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		logical_end = get_unaligned_le32(&largest->start_sect)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		    + get_unaligned_le32(&largest->nr_sects);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		/* This is for >1023 cylinders */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 		ext_cyl = (logical_end - (end_head * end_sector + end_sector))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		    / (end_head + 1) / end_sector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		ext_physical_end = ext_cyl * (end_head + 1) * end_sector +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 		    end_head * end_sector + end_sector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 		printk("scsicam_bios_param : logical_end=%d physical_end=%d ext_physical_end=%d ext_cyl=%d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 		  ,logical_end, physical_end, ext_physical_end, ext_cyl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 		if (logical_end == physical_end ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 		    (end_cyl == 1023 && ext_physical_end == logical_end)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 			geom[0] = end_head + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 			geom[1] = end_sector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 			geom[2] = (unsigned long)capacity /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 				((end_head + 1) * end_sector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 			ret = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 			goto out_free_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		printk("scsicam_bios_param : logical (%u) != physical (%u)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		       logical_end, physical_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) out_free_buf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) EXPORT_SYMBOL(scsi_partsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)  * Function : static int setsize(unsigned long capacity,unsigned int *cyls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)  *      unsigned int *hds, unsigned int *secs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)  * Purpose : to determine a near-optimal int 0x13 mapping for a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)  *      SCSI disk in terms of lost space of size capacity, storing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)  *      the results in *cyls, *hds, and *secs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)  * Returns : -1 on failure, 0 on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)  * Extracted from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)  * WORKING                                                    X3T9.2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)  * DRAFT                                                        792D
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)  * see http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)  *                                                        Revision 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)  *                                                         10-MAR-94
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)  * Information technology -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)  * SCSI-2 Common access method
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)  * transport and SCSI interface module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)  * 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)  * ANNEX A :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)  * setsize() converts a read capacity value to int 13h
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)  * head-cylinder-sector requirements. It minimizes the value for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)  * number of heads and maximizes the number of cylinders. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)  * will support rather large disks before the number of heads
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)  * will not fit in 4 bits (or 6 bits). This algorithm also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)  * minimizes the number of sectors that will be unused at the end
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)  * of the disk while allowing for very large disks to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)  * accommodated. This algorithm does not use physical geometry. 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		   unsigned int *secs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	unsigned int rv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	unsigned long heads, sectors, cylinders, temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	cylinders = 1024L;	/* Set number of cylinders to max */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	sectors = 62L;		/* Maximize sectors per track */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	temp = cylinders * sectors;	/* Compute divisor for heads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	heads = capacity / temp;	/* Compute value for number of heads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	if (capacity % temp) {	/* If no remainder, done! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		heads++;	/* Else, increment number of heads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		temp = cylinders * heads;	/* Compute divisor for sectors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 		sectors = capacity / temp;	/* Compute value for sectors per
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 						   track */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 		if (capacity % temp) {	/* If no remainder, done! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 			sectors++;	/* Else, increment number of sectors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 			temp = heads * sectors;		/* Compute divisor for cylinders */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 			cylinders = capacity / temp;	/* Compute number of cylinders */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	if (cylinders == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 		rv = (unsigned) -1;	/* Give error if 0 cylinders */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	*cyls = (unsigned int) cylinders;	/* Stuff return values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	*secs = (unsigned int) sectors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	*hds = (unsigned int) heads;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	return (rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)  * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)  * @bdev: which device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)  * @capacity: size of the disk in sectors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)  * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)  * Description : determine the BIOS mapping/geometry used for a drive in a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)  *      SCSI-CAM system, storing the results in ip as required
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)  *      by the HDIO_GETGEO ioctl().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)  * Returns : -1 on failure, 0 on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	u64 capacity64 = capacity;	/* Suppress gcc warning */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	/* try to infer mapping from partition table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	if (scsi_partsize(bdev, capacity, ip))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	if (capacity64 < (1ULL << 32)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 		 * Pick some standard mapping with at most 1024 cylinders, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 		 * at most 62 sectors per track - this works up to 7905 MB.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 		ret = setsize((unsigned long)capacity, (unsigned int *)ip + 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 		       (unsigned int *)ip + 0, (unsigned int *)ip + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	 * If something went wrong, then apparently we have to return a geometry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	 * with more than 1024 cylinders.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	if (ret || ip[0] > 255 || ip[1] > 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 		if ((capacity >> 11) > 65534) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 			ip[0] = 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 			ip[1] = 63;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 			ip[0] = 64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 			ip[1] = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 		if (capacity > 65535*63*255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 			ip[2] = 65535;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 			ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) EXPORT_SYMBOL(scsicam_bios_param);