162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * lowlevel.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * PURPOSE
662306a36Sopenharmony_ci *  Low Level Device Routines for the UDF filesystem
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * COPYRIGHT
962306a36Sopenharmony_ci *  (C) 1999-2001 Ben Fennema
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * HISTORY
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci *  03/26/99 blf  Created.
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "udfdecl.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/blkdev.h>
1962306a36Sopenharmony_ci#include <linux/cdrom.h>
2062306a36Sopenharmony_ci#include <linux/uaccess.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "udf_sb.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciunsigned int udf_get_last_session(struct super_block *sb)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct cdrom_device_info *cdi = disk_to_cdi(sb->s_bdev->bd_disk);
2762306a36Sopenharmony_ci	struct cdrom_multisession ms_info;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	if (!cdi) {
3062306a36Sopenharmony_ci		udf_debug("CDROMMULTISESSION not supported.\n");
3162306a36Sopenharmony_ci		return 0;
3262306a36Sopenharmony_ci	}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	ms_info.addr_format = CDROM_LBA;
3562306a36Sopenharmony_ci	if (cdrom_multisession(cdi, &ms_info) == 0) {
3662306a36Sopenharmony_ci		udf_debug("XA disk: %s, vol_desc_start=%d\n",
3762306a36Sopenharmony_ci			  ms_info.xa_flag ? "yes" : "no", ms_info.addr.lba);
3862306a36Sopenharmony_ci		if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
3962306a36Sopenharmony_ci			return ms_info.addr.lba;
4062306a36Sopenharmony_ci	}
4162306a36Sopenharmony_ci	return 0;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ciudf_pblk_t udf_get_last_block(struct super_block *sb)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct cdrom_device_info *cdi = disk_to_cdi(sb->s_bdev->bd_disk);
4762306a36Sopenharmony_ci	unsigned long lblock = 0;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/*
5062306a36Sopenharmony_ci	 * The cdrom layer call failed or returned obviously bogus value?
5162306a36Sopenharmony_ci	 * Try using the device size...
5262306a36Sopenharmony_ci	 */
5362306a36Sopenharmony_ci	if (!cdi || cdrom_get_last_written(cdi, &lblock) || lblock == 0) {
5462306a36Sopenharmony_ci		if (sb_bdev_nr_blocks(sb) > ~(udf_pblk_t)0)
5562306a36Sopenharmony_ci			return 0;
5662306a36Sopenharmony_ci		lblock = sb_bdev_nr_blocks(sb);
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (lblock)
6062306a36Sopenharmony_ci		return lblock - 1;
6162306a36Sopenharmony_ci	return 0;
6262306a36Sopenharmony_ci}
63