199193Sjmallett/*
299193Sjmallett * Copyright (c) 2002 Juli Mallett.  All rights reserved.
399193Sjmallett *
499193Sjmallett * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
599193Sjmallett * FreeBSD project.  Redistribution and use in source and binary forms, with
699193Sjmallett * or without modification, are permitted provided that the following
799193Sjmallett * conditions are met:
899193Sjmallett *
999193Sjmallett * 1. Redistribution of source code must retain the above copyright notice,
1099193Sjmallett *    this list of conditions and the following disclaimer.
1199193Sjmallett * 2. Redistribution in binary form must reproduce the above copyright
1299193Sjmallett *    notice, this list of conditions and the following disclaimer in the
1399193Sjmallett *    documentation and/or other materials provided with the distribution.
1499193Sjmallett *
1599193Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1699193Sjmallett * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1799193Sjmallett * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1899193Sjmallett * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
1999193Sjmallett * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2099193Sjmallett * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2199193Sjmallett * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2299193Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2399193Sjmallett * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
2499193Sjmallett * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2599193Sjmallett * POSSIBILITY OF SUCH DAMAGE.
2699193Sjmallett */
2799193Sjmallett
2899193Sjmallett#include <sys/cdefs.h>
2999193Sjmallett__FBSDID("$FreeBSD$");
3099193Sjmallett
3199193Sjmallett#include <sys/param.h>
3299193Sjmallett#include <sys/mount.h>
33174668Sphk#include <sys/disk.h>
3499193Sjmallett#include <sys/disklabel.h>
3599193Sjmallett#include <sys/stat.h>
3699193Sjmallett
3799193Sjmallett#include <ufs/ufs/ufsmount.h>
3899193Sjmallett#include <ufs/ufs/dinode.h>
3999193Sjmallett#include <ufs/ffs/fs.h>
4099193Sjmallett
4199193Sjmallett#include <errno.h>
42109766Sjmallett#include <fcntl.h>
4399193Sjmallett#include <stdio.h>
44120874Sphk#include <stdlib.h>
4599193Sjmallett#include <string.h>
4699193Sjmallett#include <unistd.h>
4799193Sjmallett
4899193Sjmallett#include <libufs.h>
4999193Sjmallett
5099193Sjmallettssize_t
5199193Sjmallettbread(struct uufsd *disk, ufs2_daddr_t blockno, void *data, size_t size)
5299193Sjmallett{
53120874Sphk	void *p2;
5499193Sjmallett	ssize_t cnt;
5599193Sjmallett
56109462Sjmallett	ERROR(disk, NULL);
5799193Sjmallett
58120874Sphk	p2 = data;
5999193Sjmallett	/*
60120874Sphk	 * XXX: various disk controllers require alignment of our buffer
61120874Sphk	 * XXX: which is stricter than struct alignment.
62120874Sphk	 * XXX: Bounce the buffer if not 64 byte aligned.
63120874Sphk	 * XXX: this can be removed if/when the kernel is fixed
6499193Sjmallett	 */
65120874Sphk	if (((intptr_t)data) & 0x3f) {
66120874Sphk		p2 = malloc(size);
67190646Sdelphij		if (p2 == NULL) {
68120874Sphk			ERROR(disk, "allocate bounce buffer");
69190646Sdelphij			goto fail;
70190646Sdelphij		}
71120874Sphk	}
72120874Sphk	cnt = pread(disk->d_fd, p2, size, (off_t)(blockno * disk->d_bsize));
73111111Sjmallett	if (cnt == -1) {
74111111Sjmallett		ERROR(disk, "read error from block device");
75111111Sjmallett		goto fail;
7699193Sjmallett	}
77111111Sjmallett	if (cnt == 0) {
78111111Sjmallett		ERROR(disk, "end of file from block device");
79111111Sjmallett		goto fail;
80111111Sjmallett	}
81111111Sjmallett	if ((size_t)cnt != size) {
82111111Sjmallett		ERROR(disk, "short read or read error from block device");
83111111Sjmallett		goto fail;
84111111Sjmallett	}
85120874Sphk	if (p2 != data) {
86120874Sphk		memcpy(data, p2, size);
87120874Sphk		free(p2);
88120874Sphk	}
89116084Sjmallett	return (cnt);
90120874Sphkfail:	memset(data, 0, size);
91120874Sphk	if (p2 != data) {
92120874Sphk		free(p2);
93120874Sphk	}
94116084Sjmallett	return (-1);
9599193Sjmallett}
9699193Sjmallett
9799193Sjmallettssize_t
9899193Sjmallettbwrite(struct uufsd *disk, ufs2_daddr_t blockno, const void *data, size_t size)
9999193Sjmallett{
10099193Sjmallett	ssize_t cnt;
101110066Sjmallett	int rv;
102120874Sphk	void *p2 = NULL;
10399193Sjmallett
104109462Sjmallett	ERROR(disk, NULL);
10599193Sjmallett
106110066Sjmallett	rv = ufs_disk_write(disk);
107110066Sjmallett	if (rv == -1) {
108109766Sjmallett		ERROR(disk, "failed to open disk for writing");
109116084Sjmallett		return (-1);
110109766Sjmallett	}
111109766Sjmallett
112120874Sphk	/*
113120874Sphk	 * XXX: various disk controllers require alignment of our buffer
114120874Sphk	 * XXX: which is stricter than struct alignment.
115120874Sphk	 * XXX: Bounce the buffer if not 64 byte aligned.
116120874Sphk	 * XXX: this can be removed if/when the kernel is fixed
117120874Sphk	 */
118120874Sphk	if (((intptr_t)data) & 0x3f) {
119120874Sphk		p2 = malloc(size);
120190646Sdelphij		if (p2 == NULL) {
121120874Sphk			ERROR(disk, "allocate bounce buffer");
122190646Sdelphij			return (-1);
123190646Sdelphij		}
124120874Sphk		memcpy(p2, data, size);
125120874Sphk		data = p2;
126120874Sphk	}
12799193Sjmallett	cnt = pwrite(disk->d_fd, data, size, (off_t)(blockno * disk->d_bsize));
128120874Sphk	if (p2 != NULL)
129120874Sphk		free(p2);
130111111Sjmallett	if (cnt == -1) {
131112850Sjmallett		ERROR(disk, "write error to block device");
132116084Sjmallett		return (-1);
133111111Sjmallett	}
134111111Sjmallett	if ((size_t)cnt != size) {
135109462Sjmallett		ERROR(disk, "short write to block device");
136116084Sjmallett		return (-1);
13799193Sjmallett	}
138109766Sjmallett
139116084Sjmallett	return (cnt);
14099193Sjmallett}
141174668Sphk
142228349Srmh#ifdef __FreeBSD_kernel__
143228349Srmh
144228349Srmhstatic int
145228349Srmhberase_helper(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
146228349Srmh{
147228349Srmh	off_t ioarg[2];
148228349Srmh
149228349Srmh	ioarg[0] = blockno * disk->d_bsize;
150228349Srmh	ioarg[1] = size;
151228349Srmh	return (ioctl(disk->d_fd, DIOCGDELETE, ioarg));
152228349Srmh}
153228349Srmh
154228349Srmh#else
155228349Srmh
156228349Srmhstatic int
157228349Srmhberase_helper(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
158228349Srmh{
159228349Srmh	char *zero_chunk;
160228349Srmh	off_t offset, zero_chunk_size, pwrite_size;
161228349Srmh	int rv;
162228349Srmh
163228349Srmh	offset = blockno * disk->d_bsize;
164228349Srmh	zero_chunk_size = 65536 * disk->d_bsize;
165228349Srmh	zero_chunk = calloc(1, zero_chunk_size);
166228349Srmh	if (zero_chunk == NULL) {
167228349Srmh		ERROR(disk, "failed to allocate memory");
168228349Srmh		return (-1);
169228349Srmh	}
170228349Srmh	while (size > 0) {
171228349Srmh		pwrite_size = size;
172228349Srmh		if (pwrite_size > zero_chunk_size)
173228349Srmh			pwrite_size = zero_chunk_size;
174228349Srmh		rv = pwrite(disk->d_fd, zero_chunk, pwrite_size, offset);
175228349Srmh		if (rv == -1) {
176228349Srmh			ERROR(disk, "failed writing to disk");
177228349Srmh			break;
178228349Srmh		}
179228349Srmh		size -= rv;
180228349Srmh		offset += rv;
181228349Srmh		rv = 0;
182228349Srmh	}
183228349Srmh	free(zero_chunk);
184228349Srmh	return (rv);
185228349Srmh}
186228349Srmh
187228349Srmh#endif
188228349Srmh
189174668Sphkint
190174668Sphkberase(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
191174668Sphk{
192174668Sphk	int rv;
193174668Sphk
194174668Sphk	ERROR(disk, NULL);
195174668Sphk	rv = ufs_disk_write(disk);
196174668Sphk	if (rv == -1) {
197174668Sphk		ERROR(disk, "failed to open disk for writing");
198174668Sphk		return(rv);
199174668Sphk	}
200228349Srmh	return (berase_helper(disk, blockno, size));
201174668Sphk}
202