xref: /haiku/src/system/kernel/disk_device_manager/KDiskDevice.cpp (revision 1b8f7f13a3dc70e0e903cb94248220b40b732204)
1 // KDiskDevice.cpp
2 
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <stdio.h>
6 #include <unistd.h>
7 
8 #include <KernelExport.h>
9 #include <Drivers.h>
10 
11 #include "ddm_userland_interface.h"
12 #include "KDiskDevice.h"
13 #include "KDiskDeviceUtils.h"
14 #include "KShadowPartition.h"
15 #include "KPath.h"
16 #include "UserDataWriter.h"
17 
18 // debugging
19 //#define DBG(x)
20 #define DBG(x) x
21 #define OUT dprintf
22 
23 // constructor
24 KDiskDevice::KDiskDevice(partition_id id)
25 	: KPhysicalPartition(id),
26 	  fDeviceData(),
27 	  fLocker("diskdevice"),
28 	  fFD(-1),
29 	  fMediaStatus(B_ERROR),
30 	  fShadowOwner(-1)
31 {
32 	Unset();
33 	fDevice = this;
34 	fPublished = true;
35 }
36 
37 // destructor
38 KDiskDevice::~KDiskDevice()
39 {
40 	Unset();
41 }
42 
43 // SetTo
44 status_t
45 KDiskDevice::SetTo(const char *path)
46 {
47 	// check initialization and parameter
48 	status_t error = InitCheck();
49 	if (error != B_OK)
50 		return error;
51 	if (!path)
52 		return B_BAD_VALUE;
53 	Unset();
54 	// set the path
55 	error = set_string(fDeviceData.path, path);
56 	if (error != B_OK)
57 		return error;
58 	// open the device
59 	fFD = open(path, O_RDONLY);
60 	if (fFD < 0)
61 		return errno;
62 	// get media status
63 	error = GetMediaStatus(&fMediaStatus);
64 	if (error != B_OK)
65 		return error;
66 	if (fMediaStatus == B_DEV_MEDIA_CHANGED)
67 		fMediaStatus = B_OK;
68 	// get device geometry
69 	if (fMediaStatus == B_OK) {
70 		error = GetGeometry(&fDeviceData.geometry);
71 		if (error != B_OK)
72 			return error;
73 	} else {
74 		// no media: try to get the device geometry, but don't fail, if
75 		// we can't get it
76 		GetGeometry(&fDeviceData.geometry);
77 	}
78 	// set device flags
79 	if (fDeviceData.geometry.removable)
80 		SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_REMOVABLE);
81 	if (fMediaStatus == B_OK)
82 		SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_HAS_MEDIA);
83 	if (fDeviceData.geometry.read_only)
84 		SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_READ_ONLY);
85 	if (fDeviceData.geometry.write_once)
86 		SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_WRITE_ONCE);
87 	// update partition data
88 	_InitPartitionData();
89 	return B_OK;
90 }
91 
92 // Unset
93 void
94 KDiskDevice::Unset()
95 {
96 	if (fFD >= 0) {
97 		close(fFD);
98 		fFD = -1;
99 	}
100 	fMediaStatus = B_ERROR;
101 	fShadowOwner = -1;
102 	fDeviceData.id = -1;
103 	fDeviceData.flags = 0;
104 	if (fDeviceData.path) {
105 		free(fDeviceData.path);
106 		fDeviceData.path = NULL;
107 	}
108 	fDeviceData.geometry.bytes_per_sector = 0;
109 	fDeviceData.geometry.sectors_per_track = 0;
110 	fDeviceData.geometry.cylinder_count = 0;
111 	fDeviceData.geometry.head_count = 0;
112 	fDeviceData.geometry.device_type = B_DISK;
113 	fDeviceData.geometry.removable = true;
114 	fDeviceData.geometry.read_only = true;
115 	fDeviceData.geometry.write_once = false;
116 }
117 
118 // InitCheck
119 status_t
120 KDiskDevice::InitCheck() const
121 {
122 	return fLocker.InitCheck();
123 }
124 
125 // ReadLock
126 bool
127 KDiskDevice::ReadLock()
128 {
129 	return fLocker.ReadLock();
130 }
131 
132 // ReadUnlock
133 void
134 KDiskDevice::ReadUnlock()
135 {
136 	fLocker.ReadUnlock();
137 }
138 
139 // IsReadLocked
140 bool
141 KDiskDevice::IsReadLocked(bool orWriteLocked)
142 {
143 	return fLocker.IsReadLocked(orWriteLocked);
144 }
145 
146 // WriteLock
147 bool
148 KDiskDevice::WriteLock()
149 {
150 	return fLocker.WriteLock();
151 }
152 
153 // WriteUnlock
154 void
155 KDiskDevice::WriteUnlock()
156 {
157 	fLocker.WriteUnlock();
158 }
159 
160 // IsWriteLocked
161 bool
162 KDiskDevice::IsWriteLocked()
163 {
164 	return fLocker.IsWriteLocked();
165 }
166 
167 // PrepareForRemoval
168 bool
169 KDiskDevice::PrepareForRemoval()
170 {
171 	if (ShadowOwner() >= 0)
172 		DeleteShadowDevice();
173 	return KPhysicalPartition::PrepareForRemoval();
174 }
175 
176 // SetID
177 void
178 KDiskDevice::SetID(partition_id id)
179 {
180 	KPhysicalPartition::SetID(id);
181 	fDeviceData.id = id;
182 }
183 
184 // PublishDevice
185 status_t
186 KDiskDevice::PublishDevice()
187 {
188 	// PublishDevice() and UnpublishDevice() are no-ops for KDiskDevices,
189 	// since they are always published.
190 	return B_OK;
191 }
192 
193 // UnpublishDevice
194 status_t
195 KDiskDevice::UnpublishDevice()
196 {
197 	// PublishDevice() and UnpublishDevice() are no-ops for KDiskDevices,
198 	// since they are always published.
199 	return B_OK;
200 }
201 
202 
203 // SetDeviceFlags
204 void
205 KDiskDevice::SetDeviceFlags(uint32 flags)
206 {
207 	fDeviceData.flags = flags;
208 }
209 
210 // DeviceFlags
211 uint32
212 KDiskDevice::DeviceFlags() const
213 {
214 	return fDeviceData.flags;
215 }
216 
217 // IsReadOnlyMedia
218 bool
219 KDiskDevice::IsReadOnlyMedia() const
220 {
221 	return fDeviceData.geometry.read_only;
222 }
223 
224 // IsWriteOnce
225 bool
226 KDiskDevice::IsWriteOnce() const
227 {
228 	return fDeviceData.geometry.write_once;
229 }
230 
231 // IsRemovable
232 bool
233 KDiskDevice::IsRemovable() const
234 {
235 	return fDeviceData.geometry.removable;
236 }
237 
238 // HasMedia
239 bool
240 KDiskDevice::HasMedia() const
241 {
242 	return (fMediaStatus == B_OK);
243 }
244 
245 // SetPath
246 status_t
247 KDiskDevice::SetPath(const char *path)
248 {
249 	return set_string(fDeviceData.path, path);
250 }
251 
252 // Path
253 const char *
254 KDiskDevice::Path() const
255 {
256 	return fDeviceData.path;
257 }
258 
259 // GetPath
260 status_t
261 KDiskDevice::GetPath(KPath *path) const
262 {
263 	if (!path || path->InitCheck() != B_OK)
264 		return B_BAD_VALUE;
265 	if (!fDeviceData.path)
266 		return B_NO_INIT;
267 	return path->SetPath(fDeviceData.path);
268 }
269 
270 // SetFD
271 void
272 KDiskDevice::SetFD(int fd)
273 {
274 	fFD = fd;
275 }
276 
277 // FD
278 int
279 KDiskDevice::FD() const
280 {
281 	return fFD;
282 }
283 
284 // DeviceData
285 disk_device_data *
286 KDiskDevice::DeviceData()
287 {
288 	return &fDeviceData;
289 }
290 
291 // DeviceData
292 const disk_device_data *
293 KDiskDevice::DeviceData() const
294 {
295 	return &fDeviceData;
296 }
297 
298 // CreateShadowDevice
299 status_t
300 KDiskDevice::CreateShadowDevice(team_id team)
301 {
302 	if (fShadowOwner >= 0 || team < 0 || !HasMedia())
303 		return B_BAD_VALUE;
304 	// create the shadow partitions
305 	status_t error = CreateShadowPartition();
306 	if (error == B_OK)
307 		SetShadowOwner(team);
308 	return error;
309 }
310 
311 // DeleteShadowDevice
312 status_t
313 KDiskDevice::DeleteShadowDevice()
314 {
315 	if (fShadowOwner < 0)
316 		return B_BAD_VALUE;
317 	UnsetShadowPartition(true);
318 	SetShadowOwner(-1);
319 	return B_OK;
320 }
321 
322 // SetShadowOwner
323 void
324 KDiskDevice::SetShadowOwner(team_id team)
325 {
326 	fShadowOwner = team;
327 }
328 
329 // ShadowOwner
330 team_id
331 KDiskDevice::ShadowOwner() const
332 {
333 	return fShadowOwner;
334 }
335 
336 // WriteUserData
337 void
338 KDiskDevice::WriteUserData(UserDataWriter &writer, user_partition_data *data)
339 {
340 	return KPhysicalPartition::WriteUserData(writer, data);
341 }
342 
343 // WriteUserData
344 void
345 KDiskDevice::WriteUserData(UserDataWriter &writer, bool shadow)
346 {
347 	KPartition *partition = shadow ? ShadowPartition() : static_cast<KPartition *>(this);
348 	if (!partition)
349 		partition = this;
350 	user_disk_device_data *data
351 		= writer.AllocateDeviceData(partition->CountChildren());
352 	char *path = writer.PlaceString(Path());
353 	if (data) {
354 		data->device_flags = DeviceFlags();
355 		data->path = path;
356 		writer.AddRelocationEntry(&data->path);
357 		partition->WriteUserData(writer, &data->device_partition_data);
358 	} else
359 		partition->WriteUserData(writer, NULL);
360 }
361 
362 // Dump
363 void
364 KDiskDevice::Dump(bool deep, int32 level)
365 {
366 	OUT("device %ld: %s\n", ID(), Path());
367 	OUT("  media status:      %s\n", strerror(fMediaStatus));
368 	OUT("  device flags:      %lx\n", DeviceFlags());
369 	if (fMediaStatus == B_OK)
370 		KPhysicalPartition::Dump(deep, 0);
371 }
372 
373 // GetMediaStatus
374 status_t
375 KDiskDevice::GetMediaStatus(status_t *mediaStatus)
376 {
377 	status_t error = B_OK;
378 	if (ioctl(fFD, B_GET_MEDIA_STATUS, mediaStatus) != 0)
379 		error = errno;
380 	// maybe the device driver doesn't implement this ioctl -- see, if getting
381 	// the device geometry succeeds
382 	if (error != B_OK) {
383 		device_geometry geometry;
384 		if (GetGeometry(&geometry) == B_OK) {
385 			// if the device is not removable, we can ignore the failed ioctl
386 			// and return a media status of B_OK
387 			if (!geometry.removable) {
388 				error = B_OK;
389 				*mediaStatus = B_OK;
390 			}
391 		}
392 	}
393 	return error;
394 }
395 
396 // GetGeometry
397 status_t
398 KDiskDevice::GetGeometry(device_geometry *geometry)
399 {
400 	if (ioctl(fFD, B_GET_GEOMETRY, geometry) != 0)
401 		return errno;
402 	return B_OK;
403 }
404 
405 // _InitPartitionData
406 void
407 KDiskDevice::_InitPartitionData()
408 {
409 	fDeviceData.id = fPartitionData.id;
410 	fPartitionData.block_size = fDeviceData.geometry.bytes_per_sector;
411 	fPartitionData.offset = 0;
412 	fPartitionData.size = (off_t)fPartitionData.block_size
413 		* fDeviceData.geometry.sectors_per_track
414 		* fDeviceData.geometry.cylinder_count
415 		* fDeviceData.geometry.head_count;
416 	fPartitionData.flags |= B_PARTITION_IS_DEVICE;
417 }
418 
419