The Pedigree Project 0.1
ScsiDisk.h
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#ifndef SCSIDISK_H
21#define SCSIDISK_H
22#include "pedigree/kernel/TargetInfo.h"
23#include "pedigree/kernel/compiler.h"
24#include "pedigree/kernel/machine/Disk.h"
25#include "pedigree/kernel/process/Mutex.h"
26#include "pedigree/kernel/process/OperationBarrier.h"
27#include "pedigree/kernel/process/TerminationDeferral.h"
28#include "pedigree/kernel/process/Thread.h"
29#include "pedigree/kernel/process/WaitQueue.h"
30#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
31#include "pedigree/kernel/processor/types.h"
32#include "pedigree/kernel/utilities/Cache.h"
33#include "pedigree/kernel/utilities/CacheConstants.h"
34#include "pedigree/kernel/utilities/String.h"
35#include "pedigree/kernel/utilities/Vector.h"
36
37#include <config.h>
38
39class ScsiCommand;
40
41class EXPORTED_PUBLIC ScsiDisk : public Disk {
42 private:
43 enum ScsiPeripheralType {
44 BlockDevice = 0x00,
45 SequentialDevice = 0x01,
46 PrinterDevice = 0x02,
47 ProcessorDevice = 0x03,
48 WriteOnceDevice = 0x04,
49 CdDvdDevice = 0x05,
50 OpticalMemoryDevice = 0x07,
51 MediumChangerDevice = 0x08,
52 ArrayDevice = 0x0C,
53 EnclosureDevice = 0x0D,
54 NoDevice = 0x1F,
55 };
56
57 public:
58 struct Sense {
59 uint8_t ResponseCode;
60 uint8_t Obsolete;
61 uint32_t SenseKey : 4;
62 uint32_t rsvd : 1;
63 uint32_t ili : 1;
64 uint32_t eom : 1;
65 uint32_t filemark : 1;
66 uint32_t info;
67 uint8_t addLen;
68 uint32_t commandInfo;
69 uint8_t Asc;
70 uint8_t AscQ;
71 uint8_t fieldCode;
72 uint8_t senseKeySpecific[3];
73 } PACKED;
74
75 struct Inquiry {
76 uint8_t Peripheral;
77 uint8_t Removable;
78 uint8_t Version;
79 uint8_t Flags1;
80 uint8_t AddLength;
81 uint8_t Rsvd[2];
82 uint8_t Flags2;
83 uint8_t VendIdent[8];
84 uint8_t ProdIdent[16];
85 uint8_t ProdRev[4];
86 } PACKED;
87
88 struct Capacity {
89 uint32_t LBA;
90 uint32_t BlockSize;
91 } PACKED;
92
93 explicit ScsiDisk(size_t cacheConstraints = PhysicalMemoryManager::below4GB);
94 virtual ~ScsiDisk();
95
96#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
97 using HostedReadRequestHook = void (*)(ScsiDisk*, uint64_t, void*);
98 static void setHostedReadRequestHookForTest(HostedReadRequestHook hook, void* context);
99#endif
100
103 void shutdownCache(bool deviceAvailable = true);
104 virtual void shutdownDeviceCache();
105 bool hasNoCacheLoans();
106
107 bool initialise(class ScsiController* pController, size_t nUnit);
108
109 virtual BufferView read(uint64_t location);
110 bool readInto(uint64_t location, void* buffer, size_t length) override;
111 bool readIntoBatch(ReadBuffer* buffers, size_t count) override;
112 bool writeFrom(uint64_t location, const void* buffer, size_t length) override;
113 bool writeFromBatch(WriteBuffer* buffers, size_t count) override;
114 bool syncData() override;
115 virtual void write(uint64_t location);
116 virtual void flush(uint64_t location);
117 virtual bool sync(uint64_t location, bool async);
118 MUST_USE_RESULT virtual bool syncAll();
119 bool zero(uint64_t location, size_t length) override;
120 bool syncPages(const uint64_t* locations, size_t count) override;
121 MUST_USE_RESULT virtual bool retireCachePage(uint64_t location);
122 virtual void align(uint64_t location);
123
124 virtual void getName(String& str) {
125 str = String("SCSI Disk");
126 }
127
128 // These are the internal functions that the controller calls when it is
129 // ready to process our request.
130 virtual uint64_t doRead(uint64_t location);
131 virtual uint64_t doWrite(uint64_t location);
132 virtual uint64_t doWriteDirectPhysical(uint64_t location, uintptr_t page,
133 physical_uintptr_t physical);
134 virtual uint64_t doSync(uint64_t location);
135 virtual PagingStatus doPagingTransfer(PagingOperation operation, uint64_t offset, void* page);
136
137 // This value is outside every valid byte location, including a maximal disk.
138 // It is reserved for SCSI_REQUEST_SYNC and never enters cache page arithmetic.
139 static constexpr uint64_t SyncWholeDevice = ~uint64_t{0};
140
141 virtual size_t getSize() const {
142 return m_NumBlocks * m_NativeBlockSize;
143 }
144
145 virtual size_t getBlockCount() const {
146 return m_NumBlocks;
147 }
148
149 virtual size_t getBlockSize() const {
150 return m_BlockSize;
151 }
152
157 virtual size_t getNativeBlockSize() const {
158 return m_NativeBlockSize;
159 }
160
161 virtual bool pin(uint64_t location);
162 virtual void unpin(uint64_t location);
163
164 protected:
165 BufferView acquireView(uint64_t location, bool writable, uint64_t& token) override;
166 void releaseView(uint64_t token, bool writable) override;
167
168 virtual bool supportsBufferTransfers() const {
169 return false;
170 }
171 virtual bool supportsDirectCacheWrite() const {
172 return false;
173 }
174 virtual Device* dmaDevice() const {
175 return nullptr;
176 }
177 virtual bool transferBuffer(uint64_t location, void* buffer, size_t length, bool writing);
178 virtual bool transferReadBuffers(ReadBuffer* buffers, size_t count);
179 virtual bool transferWriteBuffers(WriteBuffer* buffers, size_t count);
180 static bool syncCacheBatch(const Cache::WritebackPage* pages, size_t count, void* context);
181
182 ScsiController* acquirePagingController(OperationBarrier::Lease& use);
183 PagingStatus preparePagingCache(PagingTransport& transport);
184
192 virtual size_t getCacheFillSize() const {
194 }
195
204 size_t getCacheFillLength(uint64_t location) const;
205
206 Cache& getCache() {
207 return m_Cache;
208 }
209
210 Inquiry* getInquiry() const {
211 return m_Inquiry;
212 }
213
214 private:
216 public:
217 CacheRangeAdmission(ScsiDisk& disk, uint64_t start, size_t length, bool retire);
219
220 private:
221 friend class ScsiDisk;
222
223 NOT_COPYABLE_OR_ASSIGNABLE(CacheRangeAdmission);
224
225 static void discard(void* context);
226
227 ScsiDisk& m_Disk;
228 uint64_t m_Start;
229 size_t m_Length;
230 bool m_Retire;
231 bool m_Linked;
232 CacheRangeAdmission* m_Previous;
233 CacheRangeAdmission* m_Next;
234 TerminationDeferral m_TerminationDeferral;
235 Thread::StackDiscardScope m_StackDiscardScope;
236 };
237
238 void enterCacheRange(CacheRangeAdmission& admission);
239 void leaveCacheRange(CacheRangeAdmission& admission);
240 bool cacheRangeBlocked(const CacheRangeAdmission& admission) const;
241 bool transferBufferRange(uint64_t location, void* buffer, size_t length, bool writing);
242 static bool cacheRangesOverlap(uint64_t firstStart, size_t firstLength, uint64_t secondStart,
243 size_t secondLength);
244
245 bool unitReady();
246
247 bool readSense(Sense* s);
248
249 bool sendCommand(ScsiCommand* pCommand, uintptr_t pRespBuffer, uint16_t nRespBytes,
250 bool bWrite = false);
251
252 bool getCapacityInternal(size_t* blockNumber, size_t* blockSize);
253
255 bool flushCachePage(uint64_t location, uintptr_t page);
256
258 bool writePageBuffer(uint64_t location, uintptr_t page);
259
261 size_t getCachePageValidLength(uint64_t location) const;
262
264 static bool retireCachePageCallback(uintptr_t key, uintptr_t page, void* meta);
265
267 uint64_t getAlignmentPoint(uint64_t location) const;
268 bool hasShiftedCacheAlignment() const;
269
270 static bool cacheCallback(CacheConstants::CallbackCause cause, uintptr_t loc, uintptr_t page,
271 void* meta);
272
273 class ScsiController* m_pController;
274 size_t m_nUnit;
275
276 Cache m_Cache;
277 Inquiry* m_Inquiry;
278
279 WaitQueue m_CacheRangeWaiters;
280 CacheRangeAdmission* m_FirstCacheRangeAdmission;
281 CacheRangeAdmission* m_LastCacheRangeAdmission;
282
283#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
284 static Mutex m_HostedReadRequestHookLock;
285 static HostedReadRequestHook m_HostedReadRequestHook;
286 static void* m_HostedReadRequestHookContext;
287#endif
288
289 mutable Mutex m_AlignmentLock;
290 Vector<uint64_t> m_AlignPoints;
291 bool m_HasShiftedCacheAlignment;
292
293 size_t m_NumBlocks;
294 size_t m_BlockSize;
295 size_t m_NativeBlockSize;
296
297 ScsiPeripheralType m_DeviceType;
298
300 virtual size_t defaultBlockSize() {
301 return m_BlockSize;
302 }
303
304 public:
306 MUST_USE_RESULT virtual uint64_t doWriteDirect(uint64_t location, uintptr_t page);
307};
308
309#endif
Definition Cache.h:207
Definition Disk.h:35
virtual bool sync(uint64_t location, bool async)
Definition Disk.cc:358
virtual void align(uint64_t location)
Sets the page boundary alignment after a specific location on the disk.
Definition Disk.cc:342
virtual BufferView read(uint64_t location)
Definition Disk.cc:163
virtual MUST_USE_RESULT bool readIntoBatch(ReadBuffer *buffers, size_t count)
Definition Disk.cc:199
virtual MUST_USE_RESULT bool zero(uint64_t location, size_t length)
Definition Disk.cc:387
virtual void unpin(uint64_t location)=0
virtual MUST_USE_RESULT bool writeFromBatch(WriteBuffer *buffers, size_t count)
Definition Disk.cc:285
virtual MUST_USE_RESULT bool readInto(uint64_t location, void *buffer, size_t length)
Definition Disk.cc:219
virtual MUST_USE_RESULT bool syncPages(const uint64_t *locations, size_t count)
Definition Disk.cc:362
virtual void write(uint64_t location)
Definition Disk.cc:340
virtual void flush(uint64_t location)
Flush a cached page to disk.
Definition Disk.cc:356
virtual MUST_USE_RESULT bool pin(uint64_t location)=0
Pins a cache page.
virtual MUST_USE_RESULT bool retireCachePage(uint64_t location)
Definition Disk.cc:379
virtual MUST_USE_RESULT bool syncData()
Definition Disk.cc:299
virtual MUST_USE_RESULT bool syncAll()
Definition Disk.cc:375
Definition Mutex.h:56
virtual size_t getSize() const
Gets the size of the disk.
Definition ScsiDisk.h:141
virtual size_t getCacheFillSize() const
Definition ScsiDisk.h:192
virtual size_t defaultBlockSize()
Definition ScsiDisk.h:300
virtual void getName(String &str)
Definition ScsiDisk.h:124
virtual size_t getBlockSize() const
Gets the preferred I/O extent of the disk.
Definition ScsiDisk.h:149
virtual size_t getNativeBlockSize() const
Definition ScsiDisk.h:157
static constexpr size_t getPageSize() noexcept
Definition TargetInfo.h:40
A vector / dynamic array.
Definition Vector.h:33