aac_disk.c (82830) | aac_disk.c (83114) |
---|---|
1/*- 2 * Copyright (c) 2000 Michael Smith 3 * Copyright (c) 2001 Scott Long 4 * Copyright (c) 2000 BSDi 5 * Copyright (c) 2001 Adaptec, Inc. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without --- 12 unchanged lines hidden (view full) --- 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * | 1/*- 2 * Copyright (c) 2000 Michael Smith 3 * Copyright (c) 2001 Scott Long 4 * Copyright (c) 2000 BSDi 5 * Copyright (c) 2001 Adaptec, Inc. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without --- 12 unchanged lines hidden (view full) --- 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * |
29 * $FreeBSD: head/sys/dev/aac/aac_disk.c 82830 2001-09-02 23:16:40Z scottl $ | 29 * $FreeBSD: head/sys/dev/aac/aac_disk.c 83114 2001-09-05 20:43:02Z scottl $ |
30 */ 31 32#include "opt_aac.h" 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/kernel.h> 37#include <sys/sysctl.h> --- 28 unchanged lines hidden (view full) --- 66static d_open_t aac_disk_open; 67static d_close_t aac_disk_close; 68static d_strategy_t aac_disk_strategy; 69static d_dump_t aac_disk_dump; 70 71#define AAC_DISK_CDEV_MAJOR 151 72 73static struct cdevsw aac_disk_cdevsw = { | 30 */ 31 32#include "opt_aac.h" 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/kernel.h> 37#include <sys/sysctl.h> --- 28 unchanged lines hidden (view full) --- 66static d_open_t aac_disk_open; 67static d_close_t aac_disk_close; 68static d_strategy_t aac_disk_strategy; 69static d_dump_t aac_disk_dump; 70 71#define AAC_DISK_CDEV_MAJOR 151 72 73static struct cdevsw aac_disk_cdevsw = { |
74 /* open */ aac_disk_open, 75 /* close */ aac_disk_close, 76 /* read */ physread, 77 /* write */ physwrite, 78 /* ioctl */ noioctl, 79 /* poll */ nopoll, 80 /* mmap */ nommap, 81 /* strategy */ aac_disk_strategy, 82 /* name */ "aacd", 83 /* maj */ AAC_DISK_CDEV_MAJOR, 84 /* dump */ aac_disk_dump, 85 /* psize */ nopsize, 86 /* flags */ D_DISK, | 74 /* open */ aac_disk_open, 75 /* close */ aac_disk_close, 76 /* read */ physread, 77 /* write */ physwrite, 78 /* ioctl */ noioctl, 79 /* poll */ nopoll, 80 /* mmap */ nommap, 81 /* strategy */ aac_disk_strategy, 82 /* name */ "aacd", 83 /* maj */ AAC_DISK_CDEV_MAJOR, 84 /* dump */ aac_disk_dump, 85 /* psize */ nopsize, 86 /* flags */ D_DISK, |
87#if __FreeBSD_version < 500005 | 87#if __FreeBSD_version < 500005 |
88 /* bmaj */ -1 | 88 /* bmaj */ -1 |
89#endif 90}; 91 92devclass_t aac_disk_devclass; 93static struct cdevsw aac_disk_disk_cdevsw; 94#ifdef FREEBSD_4 95static int disks_registered = 0; 96#endif 97 98static device_method_t aac_disk_methods[] = { | 89#endif 90}; 91 92devclass_t aac_disk_devclass; 93static struct cdevsw aac_disk_disk_cdevsw; 94#ifdef FREEBSD_4 95static int disks_registered = 0; 96#endif 97 98static device_method_t aac_disk_methods[] = { |
99 DEVMETHOD(device_probe, aac_disk_probe), 100 DEVMETHOD(device_attach, aac_disk_attach), 101 DEVMETHOD(device_detach, aac_disk_detach), 102 { 0, 0 } | 99 DEVMETHOD(device_probe, aac_disk_probe), 100 DEVMETHOD(device_attach, aac_disk_attach), 101 DEVMETHOD(device_detach, aac_disk_detach), 102 { 0, 0 } |
103}; 104 105static driver_t aac_disk_driver = { | 103}; 104 105static driver_t aac_disk_driver = { |
106 "aacd", 107 aac_disk_methods, 108 sizeof(struct aac_disk) | 106 "aacd", 107 aac_disk_methods, 108 sizeof(struct aac_disk) |
109}; 110 111DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0); 112 113/* sysctl tunables */ 114static unsigned int aac_iosize_max = 65536; /* due to limits of the card */ 115TUNABLE_INT("hw.aac.iosize_max", &aac_iosize_max); 116 117SYSCTL_DECL(_hw_aac); 118SYSCTL_UINT(_hw_aac, OID_AUTO, iosize_max, CTLFLAG_RD, &aac_iosize_max, 0, 119 "Max I/O size per transfer to an array"); 120 121#define AAC_MAXIO 65536 122 | 109}; 110 111DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0); 112 113/* sysctl tunables */ 114static unsigned int aac_iosize_max = 65536; /* due to limits of the card */ 115TUNABLE_INT("hw.aac.iosize_max", &aac_iosize_max); 116 117SYSCTL_DECL(_hw_aac); 118SYSCTL_UINT(_hw_aac, OID_AUTO, iosize_max, CTLFLAG_RD, &aac_iosize_max, 0, 119 "Max I/O size per transfer to an array"); 120 121#define AAC_MAXIO 65536 122 |
123/****************************************************************************** | 123/* |
124 * Handle open from generic layer. 125 * 126 * This is called by the diskslice code on first open in order to get the 127 * basic device geometry paramters. 128 */ 129static int 130aac_disk_open(dev_t dev, int flags, int fmt, struct proc *p) 131{ | 124 * Handle open from generic layer. 125 * 126 * This is called by the diskslice code on first open in order to get the 127 * basic device geometry paramters. 128 */ 129static int 130aac_disk_open(dev_t dev, int flags, int fmt, struct proc *p) 131{ |
132 struct aac_disk *sc = (struct aac_disk *)dev->si_drv1; 133 struct disklabel *label; | 132 struct aac_disk *sc; 133 struct disklabel *label; |
134 | 134 |
135 debug_called(4); | 135 debug_called(4); 136 137 sc = (struct aac_disk *)dev->si_drv1; |
136 | 138 |
137 if (sc == NULL) 138 return (ENXIO); | 139 if (sc == NULL) 140 return (ENXIO); |
139 | 141 |
140 /* check that the controller is up and running */ 141 if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND) 142 return(ENXIO); | 142 /* check that the controller is up and running */ 143 if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND) 144 return(ENXIO); |
143 | 145 |
144 /* build synthetic label */ 145 label = &sc->ad_disk.d_label; 146 bzero(label, sizeof(*label)); 147 label->d_type = DTYPE_ESDI; 148 label->d_secsize = AAC_BLOCK_SIZE; 149 label->d_nsectors = sc->ad_sectors; 150 label->d_ntracks = sc->ad_heads; 151 label->d_ncylinders = sc->ad_cylinders; 152 label->d_secpercyl = sc->ad_sectors * sc->ad_heads; 153 label->d_secperunit = sc->ad_size; | 146 /* build synthetic label */ 147 label = &sc->ad_disk.d_label; 148 bzero(label, sizeof(*label)); 149 label->d_type = DTYPE_ESDI; 150 label->d_secsize = AAC_BLOCK_SIZE; 151 label->d_nsectors = sc->ad_sectors; 152 label->d_ntracks = sc->ad_heads; 153 label->d_ncylinders = sc->ad_cylinders; 154 label->d_secpercyl = sc->ad_sectors * sc->ad_heads; 155 label->d_secperunit = sc->ad_size; |
154 | 156 |
155 sc->ad_flags |= AAC_DISK_OPEN; 156 return (0); | 157 sc->ad_flags |= AAC_DISK_OPEN; 158 return (0); |
157} 158 | 159} 160 |
159/****************************************************************************** | 161/* |
160 * Handle last close of the disk device. 161 */ 162static int 163aac_disk_close(dev_t dev, int flags, int fmt, struct proc *p) 164{ | 162 * Handle last close of the disk device. 163 */ 164static int 165aac_disk_close(dev_t dev, int flags, int fmt, struct proc *p) 166{ |
165 struct aac_disk *sc = (struct aac_disk *)dev->si_drv1; | 167 struct aac_disk *sc; |
166 | 168 |
167 debug_called(4); | 169 debug_called(4); 170 171 sc = (struct aac_disk *)dev->si_drv1; |
168 | 172 |
169 if (sc == NULL) 170 return (ENXIO); | 173 if (sc == NULL) 174 return (ENXIO); |
171 | 175 |
172 sc->ad_flags &= ~AAC_DISK_OPEN; 173 return (0); | 176 sc->ad_flags &= ~AAC_DISK_OPEN; 177 return (0); |
174} 175 | 178} 179 |
176/****************************************************************************** | 180/* |
177 * Handle an I/O request. 178 */ 179static void 180aac_disk_strategy(struct bio *bp) 181{ | 181 * Handle an I/O request. 182 */ 183static void 184aac_disk_strategy(struct bio *bp) 185{ |
182 struct aac_disk *sc = (struct aac_disk *)bp->bio_dev->si_drv1; | 186 struct aac_disk *sc; |
183 | 187 |
184 debug_called(4); | 188 debug_called(4); |
185 | 189 |
186 /* bogus disk? */ 187 if (sc == NULL) { 188 bp->bio_flags |= BIO_ERROR; 189 bp->bio_error = EINVAL; 190 biodone(bp); 191 return; 192 } | 190 sc = (struct aac_disk *)bp->bio_dev->si_drv1; |
193 | 191 |
194 /* do-nothing operation? */ 195 if (bp->bio_bcount == 0) { 196 bp->bio_resid = bp->bio_bcount; 197 biodone(bp); 198 return; 199 } | 192 /* bogus disk? */ 193 if (sc == NULL) { 194 bp->bio_flags |= BIO_ERROR; 195 bp->bio_error = EINVAL; 196 biodone(bp); 197 return; 198 } |
200 | 199 |
201 /* perform accounting */ 202 devstat_start_transaction(&sc->ad_stats); | 200 /* do-nothing operation? */ 201 if (bp->bio_bcount == 0) { 202 bp->bio_resid = bp->bio_bcount; 203 biodone(bp); 204 return; 205 } |
203 | 206 |
204 /* pass the bio to the controller - it can work out who we are */ 205 aac_submit_bio(bp); 206 return; | 207 /* perform accounting */ 208 devstat_start_transaction(&sc->ad_stats); 209 210 /* pass the bio to the controller - it can work out who we are */ 211 aac_submit_bio(bp); 212 return; |
207} 208 | 213} 214 |
209/****************************************************************************** | 215/* |
210 * Dump memory out to an array 211 * 212 * This queues blocks of memory of size AAC_MAXIO to the controller and waits 213 * for the controller to complete the requests. 214 */ 215static int 216aac_disk_dump(dev_t dev) 217{ | 216 * Dump memory out to an array 217 * 218 * This queues blocks of memory of size AAC_MAXIO to the controller and waits 219 * for the controller to complete the requests. 220 */ 221static int 222aac_disk_dump(dev_t dev) 223{ |
218 struct aac_disk *ad = dev->si_drv1; 219 struct aac_softc *sc; 220 vm_offset_t addr = 0; 221 long blkcnt; 222 unsigned int count, blkno, secsize; 223 int dumppages = AAC_MAXIO / PAGE_SIZE; 224 int i, error; | 224 struct aac_disk *ad; 225 struct aac_softc *sc; 226 vm_offset_t addr; 227 long blkcnt; 228 unsigned int count, blkno, secsize; 229 int dumppages; 230 int i, error; |
225 | 231 |
226 if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize))) 227 return (error); | 232 ad = dev->si_drv1; 233 addr = 0; 234 dumppages = AAC_MAXIO / PAGE_SIZE; |
228 | 235 |
229 if (ad == NULL) 230 return (ENXIO); | 236 if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize))) 237 return (error); |
231 | 238 |
232 sc= ad->ad_controller; | 239 if (ad == NULL) 240 return (ENXIO); |
233 | 241 |
234 blkcnt = howmany(PAGE_SIZE, secsize); | 242 sc= ad->ad_controller; |
235 | 243 |
236 while (count > 0) { 237 caddr_t va = NULL; | 244 blkcnt = howmany(PAGE_SIZE, secsize); |
238 | 245 |
239 if ((count / blkcnt) < dumppages) 240 dumppages = count / blkcnt; | 246 while (count > 0) { 247 caddr_t va = NULL; |
241 | 248 |
242 for (i = 0; i < dumppages; ++i) { 243 vm_offset_t a = addr + (i * PAGE_SIZE); 244 if (is_physical_memory(a)) { 245 va = pmap_kenter_temporary(trunc_page(a), i); 246 } else { 247 va = pmap_kenter_temporary(trunc_page(0), i); 248 } 249 } | 249 if ((count / blkcnt) < dumppages) 250 dumppages = count / blkcnt; |
250 | 251 |
252 for (i = 0; i < dumppages; ++i) { 253 vm_offset_t a = addr + (i * PAGE_SIZE); 254 if (is_physical_memory(a)) { 255 va = pmap_kenter_temporary(trunc_page(a), i); 256 } else { 257 va = pmap_kenter_temporary(trunc_page(0), i); 258 } 259 } 260 |
|
251retry: | 261retry: |
252 /* 253 * Queue the block to the controller. If the queue is full, EBUSY 254 * will be returned. 255 */ 256 error = aac_dump_enqueue(ad, blkno, va, dumppages); 257 if (error && (error != EBUSY)) 258 return (error); | 262 /* 263 * Queue the block to the controller. If the queue is full, 264 * EBUSY will be returned. 265 */ 266 error = aac_dump_enqueue(ad, blkno, va, dumppages); 267 if (error && (error != EBUSY)) 268 return (error); |
259 | 269 |
260 if (!error) { 261 if (dumpstatus(addr, (long)(count * DEV_BSIZE)) < 0) 262 return (EINTR); | 270 if (!error) { 271 if (dumpstatus(addr, (long)(count * DEV_BSIZE)) < 0) 272 return (EINTR); |
263 | 273 |
264 blkno += blkcnt * dumppages; 265 count -= blkcnt * dumppages; 266 addr += PAGE_SIZE * dumppages; 267 if (count > 0) 268 continue; 269 } | 274 blkno += blkcnt * dumppages; 275 count -= blkcnt * dumppages; 276 addr += PAGE_SIZE * dumppages; 277 if (count > 0) 278 continue; 279 } |
270 | 280 |
271 /* 272 * Either the queue was full on the last attemp, or we have no more 273 * data to dump. Let the queue drain out and retry the block if 274 * the queue was full. 275 */ 276 aac_dump_complete(sc); | 281 /* 282 * Either the queue was full on the last attemp, or we have no 283 * more data to dump. Let the queue drain out and retry the 284 * block if the queue was full. 285 */ 286 aac_dump_complete(sc); |
277 | 287 |
278 if (error == EBUSY) 279 goto retry; 280 } | 288 if (error == EBUSY) 289 goto retry; 290 } |
281 | 291 |
282 return (0); | 292 return (0); |
283} 284 | 293} 294 |
285/****************************************************************************** | 295/* |
286 * Handle completion of an I/O request. 287 */ 288void 289aac_biodone(struct bio *bp) 290{ | 296 * Handle completion of an I/O request. 297 */ 298void 299aac_biodone(struct bio *bp) 300{ |
291 struct aac_disk *sc = (struct aac_disk *)bp->bio_dev->si_drv1; | 301 struct aac_disk *sc; 302 int blkno; |
292 | 303 |
293 debug_called(4); | 304 debug_called(4); |
294 | 305 |
295 devstat_end_transaction_bio(&sc->ad_stats, bp); 296 if (bp->bio_flags & BIO_ERROR) { 297 /* 298 * XXX For some reason, the disklabel seems to get zero'd out. This 299 * will cause diskerr to panic unless we pass in -1 as the blkno. 300 */ 301 int blkno = (sc->ad_label.d_nsectors) ? 0 : -1; | 306 sc = (struct aac_disk *)bp->bio_dev->si_drv1; 307 308 devstat_end_transaction_bio(&sc->ad_stats, bp); 309 if (bp->bio_flags & BIO_ERROR) { 310 blkno = (sc->ad_label.d_nsectors) ? 0 : -1; |
302#if __FreeBSD_version > 500005 | 311#if __FreeBSD_version > 500005 |
303 diskerr(bp, (char *)bp->bio_driver1, blkno, &sc->ad_label); | 312 diskerr(bp, (char *)bp->bio_driver1, blkno, &sc->ad_label); |
304#else | 313#else |
305 diskerr(bp, (char *)bp->bio_driver1, 0, blkno, &sc->ad_label); | 314 diskerr(bp, (char *)bp->bio_driver1, 0, blkno, &sc->ad_label); |
306#endif | 315#endif |
307 } 308 biodone(bp); | 316 } 317 biodone(bp); |
309} 310 | 318} 319 |
311/****************************************************************************** | 320/* |
312 * Stub only. 313 */ 314static int 315aac_disk_probe(device_t dev) 316{ 317 | 321 * Stub only. 322 */ 323static int 324aac_disk_probe(device_t dev) 325{ 326 |
318 debug_called(2); | 327 debug_called(2); |
319 | 328 |
320 return (0); | 329 return (0); |
321} 322 | 330} 331 |
323/****************************************************************************** | 332/* |
324 * Attach a unit to the controller. 325 */ 326static int 327aac_disk_attach(device_t dev) 328{ | 333 * Attach a unit to the controller. 334 */ 335static int 336aac_disk_attach(device_t dev) 337{ |
329 struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev); 330 331 debug_called(1); | 338 struct aac_disk *sc; 339 340 debug_called(1); |
332 | 341 |
333 /* initialise our softc */ 334 sc->ad_controller = 335 (struct aac_softc *)device_get_softc(device_get_parent(dev)); 336 sc->ad_container = device_get_ivars(dev); 337 sc->ad_dev = dev; | 342 sc = (struct aac_disk *)device_get_softc(dev); |
338 | 343 |
339 /* 340 * require that extended translation be enabled - other drivers read the 341 * disk! 342 */ 343 sc->ad_size = sc->ad_container->co_mntobj.Capacity; 344 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */ 345 sc->ad_heads = 255; 346 sc->ad_sectors = 63; 347 } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */ 348 sc->ad_heads = 128; 349 sc->ad_sectors = 32; 350 } else { 351 sc->ad_heads = 64; 352 sc->ad_sectors = 32; 353 } 354 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors)); | 344 /* initialise our softc */ 345 sc->ad_controller = 346 (struct aac_softc *)device_get_softc(device_get_parent(dev)); 347 sc->ad_container = device_get_ivars(dev); 348 sc->ad_dev = dev; |
355 | 349 |
356 device_printf(dev, "%uMB (%u sectors)\n", 357 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE), sc->ad_size); | 350 /* 351 * require that extended translation be enabled - other drivers read the 352 * disk! 353 */ 354 sc->ad_size = sc->ad_container->co_mntobj.Capacity; 355 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */ 356 sc->ad_heads = 255; 357 sc->ad_sectors = 63; 358 } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */ 359 sc->ad_heads = 128; 360 sc->ad_sectors = 32; 361 } else { 362 sc->ad_heads = 64; 363 sc->ad_sectors = 32; 364 } 365 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors)); |
358 | 366 |
359 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev), 360 AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS, 361 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 362 DEVSTAT_PRIORITY_ARRAY); | 367 device_printf(dev, "%uMB (%u sectors)\n", 368 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE), 369 sc->ad_size); |
363 | 370 |
364 /* attach a generic disk device to ourselves */ 365 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0, 366 &aac_disk_cdevsw, &aac_disk_disk_cdevsw); 367 sc->ad_dev_t->si_drv1 = sc; | 371 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev), 372 AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS, 373 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 374 DEVSTAT_PRIORITY_ARRAY); 375 376 /* attach a generic disk device to ourselves */ 377 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0, 378 &aac_disk_cdevsw, &aac_disk_disk_cdevsw); 379 sc->ad_dev_t->si_drv1 = sc; |
368#ifdef FREEBSD_4 | 380#ifdef FREEBSD_4 |
369 disks_registered++; | 381 disks_registered++; |
370#endif 371 | 382#endif 383 |
372 sc->ad_dev_t->si_iosize_max = aac_iosize_max; 373 sc->unit = device_get_unit(dev); | 384 sc->ad_dev_t->si_iosize_max = aac_iosize_max; 385 sc->unit = device_get_unit(dev); |
374 | 386 |
375 return (0); | 387 return (0); |
376} 377 | 388} 389 |
378/****************************************************************************** | 390/* |
379 * Disconnect ourselves from the system. 380 */ 381static int 382aac_disk_detach(device_t dev) 383{ | 391 * Disconnect ourselves from the system. 392 */ 393static int 394aac_disk_detach(device_t dev) 395{ |
384 struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev); | 396 struct aac_disk *sc; |
385 | 397 |
386 debug_called(2); | 398 debug_called(2); |
387 | 399 |
388 if (sc->ad_flags & AAC_DISK_OPEN) 389 return(EBUSY); | 400 sc = (struct aac_disk *)device_get_softc(dev); |
390 | 401 |
391 devstat_remove_entry(&sc->ad_stats); 392 disk_destroy(sc->ad_dev_t); | 402 if (sc->ad_flags & AAC_DISK_OPEN) 403 return(EBUSY); 404 405 devstat_remove_entry(&sc->ad_stats); 406 disk_destroy(sc->ad_dev_t); |
393#ifdef FREEBSD_4 | 407#ifdef FREEBSD_4 |
394 if (--disks_registered == 0) 395 cdevsw_remove(&aac_disk_cdevsw); | 408 if (--disks_registered == 0) 409 cdevsw_remove(&aac_disk_cdevsw); |
396#endif 397 | 410#endif 411 |
398 return(0); | 412 return(0); |
399} | 413} |
400 | |