aac_disk.c revision 103675
165793Smsmith/*- 265793Smsmith * Copyright (c) 2000 Michael Smith 381082Sscottl * Copyright (c) 2001 Scott Long 465793Smsmith * Copyright (c) 2000 BSDi 581082Sscottl * Copyright (c) 2001 Adaptec, Inc. 665793Smsmith * All rights reserved. 765793Smsmith * 865793Smsmith * Redistribution and use in source and binary forms, with or without 965793Smsmith * modification, are permitted provided that the following conditions 1065793Smsmith * are met: 1165793Smsmith * 1. Redistributions of source code must retain the above copyright 1265793Smsmith * notice, this list of conditions and the following disclaimer. 1365793Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1465793Smsmith * notice, this list of conditions and the following disclaimer in the 1565793Smsmith * documentation and/or other materials provided with the distribution. 1665793Smsmith * 1765793Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1865793Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1965793Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2065793Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2165793Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2265793Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2365793Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2465793Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2565793Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2665793Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2765793Smsmith * SUCH DAMAGE. 2865793Smsmith * 2965793Smsmith * $FreeBSD: head/sys/dev/aac/aac_disk.c 103675 2002-09-20 12:52:03Z phk $ 3065793Smsmith */ 3165793Smsmith 3281151Sscottl#include "opt_aac.h" 3381151Sscottl 3465793Smsmith#include <sys/param.h> 3565793Smsmith#include <sys/systm.h> 3665793Smsmith#include <sys/kernel.h> 3781154Sscottl#include <sys/sysctl.h> 3865793Smsmith 3965793Smsmith#include <dev/aac/aac_compat.h> 4065793Smsmith#include <sys/bus.h> 4165793Smsmith#include <sys/conf.h> 4265793Smsmith#include <sys/devicestat.h> 4365793Smsmith#include <sys/disk.h> 4465793Smsmith 4582527Sscottl#include <vm/vm.h> 4682527Sscottl#include <vm/pmap.h> 4782527Sscottl 4882527Sscottl#include <machine/md_var.h> 4965793Smsmith#include <machine/bus.h> 5065793Smsmith#include <sys/rman.h> 5165793Smsmith 5265793Smsmith#include <dev/aac/aacreg.h> 5370393Smsmith#include <dev/aac/aac_ioctl.h> 5465793Smsmith#include <dev/aac/aacvar.h> 5565793Smsmith 5665793Smsmith/* 5765793Smsmith * Interface to parent. 5865793Smsmith */ 5965793Smsmithstatic int aac_disk_probe(device_t dev); 6065793Smsmithstatic int aac_disk_attach(device_t dev); 6165793Smsmithstatic int aac_disk_detach(device_t dev); 6265793Smsmith 6365793Smsmith/* 6465793Smsmith * Interface to the device switch. 6565793Smsmith */ 6665793Smsmithstatic d_open_t aac_disk_open; 6765793Smsmithstatic d_close_t aac_disk_close; 6865793Smsmithstatic d_strategy_t aac_disk_strategy; 6982527Sscottlstatic d_dump_t aac_disk_dump; 7065793Smsmith 7165793Smsmith#define AAC_DISK_CDEV_MAJOR 151 7265793Smsmith 7365793Smsmithstatic struct cdevsw aac_disk_cdevsw = { 7483114Sscottl /* open */ aac_disk_open, 7583114Sscottl /* close */ aac_disk_close, 7683114Sscottl /* read */ physread, 7783114Sscottl /* write */ physwrite, 7883114Sscottl /* ioctl */ noioctl, 7983114Sscottl /* poll */ nopoll, 8083114Sscottl /* mmap */ nommap, 8183114Sscottl /* strategy */ aac_disk_strategy, 8283114Sscottl /* name */ "aacd", 8383114Sscottl /* maj */ AAC_DISK_CDEV_MAJOR, 8483114Sscottl /* dump */ aac_disk_dump, 8583114Sscottl /* psize */ nopsize, 8683114Sscottl /* flags */ D_DISK, 8782527Sscottl#if __FreeBSD_version < 500005 8883114Sscottl /* bmaj */ -1 8982527Sscottl#endif 9065793Smsmith}; 9165793Smsmith 9289112Smsmithstatic devclass_t aac_disk_devclass; 9365793Smsmithstatic struct cdevsw aac_disk_disk_cdevsw; 9465793Smsmith#ifdef FREEBSD_4 9565793Smsmithstatic int disks_registered = 0; 9665793Smsmith#endif 9765793Smsmith 9865793Smsmithstatic device_method_t aac_disk_methods[] = { 9983114Sscottl DEVMETHOD(device_probe, aac_disk_probe), 10083114Sscottl DEVMETHOD(device_attach, aac_disk_attach), 10183114Sscottl DEVMETHOD(device_detach, aac_disk_detach), 10283114Sscottl { 0, 0 } 10365793Smsmith}; 10465793Smsmith 10565793Smsmithstatic driver_t aac_disk_driver = { 10683114Sscottl "aacd", 10783114Sscottl aac_disk_methods, 10883114Sscottl sizeof(struct aac_disk) 10965793Smsmith}; 11065793Smsmith 11195350Sscottl#define AAC_MAXIO 65536 11295350Sscottl 11365793SmsmithDRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0); 11465793Smsmith 11581154Sscottl/* sysctl tunables */ 11695350Sscottlstatic unsigned int aac_iosize_max = AAC_MAXIO; /* due to limits of the card */ 11781154SscottlTUNABLE_INT("hw.aac.iosize_max", &aac_iosize_max); 11881154Sscottl 11981154SscottlSYSCTL_DECL(_hw_aac); 12081154SscottlSYSCTL_UINT(_hw_aac, OID_AUTO, iosize_max, CTLFLAG_RD, &aac_iosize_max, 0, 12182527Sscottl "Max I/O size per transfer to an array"); 12281154Sscottl 12383114Sscottl/* 12465793Smsmith * Handle open from generic layer. 12565793Smsmith * 12665793Smsmith * This is called by the diskslice code on first open in order to get the 12765793Smsmith * basic device geometry paramters. 12865793Smsmith */ 12965793Smsmithstatic int 13087310Sscottlaac_disk_open(dev_t dev, int flags, int fmt, d_thread_t *td) 13165793Smsmith{ 13283114Sscottl struct aac_disk *sc; 13383114Sscottl struct disklabel *label; 13465793Smsmith 13583114Sscottl debug_called(4); 13683114Sscottl 13783114Sscottl sc = (struct aac_disk *)dev->si_drv1; 13865793Smsmith 13983114Sscottl if (sc == NULL) 14083114Sscottl return (ENXIO); 14165793Smsmith 14283114Sscottl /* check that the controller is up and running */ 14383114Sscottl if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND) 14483114Sscottl return(ENXIO); 14565793Smsmith 14683114Sscottl /* build synthetic label */ 14783114Sscottl label = &sc->ad_disk.d_label; 14883114Sscottl bzero(label, sizeof(*label)); 14983114Sscottl label->d_type = DTYPE_ESDI; 15083114Sscottl label->d_secsize = AAC_BLOCK_SIZE; 15183114Sscottl label->d_nsectors = sc->ad_sectors; 15283114Sscottl label->d_ntracks = sc->ad_heads; 15383114Sscottl label->d_ncylinders = sc->ad_cylinders; 15483114Sscottl label->d_secpercyl = sc->ad_sectors * sc->ad_heads; 15583114Sscottl label->d_secperunit = sc->ad_size; 15665793Smsmith 15783114Sscottl sc->ad_flags |= AAC_DISK_OPEN; 15883114Sscottl return (0); 15965793Smsmith} 16065793Smsmith 16183114Sscottl/* 16265793Smsmith * Handle last close of the disk device. 16365793Smsmith */ 16465793Smsmithstatic int 16587310Sscottlaac_disk_close(dev_t dev, int flags, int fmt, d_thread_t *td) 16665793Smsmith{ 16783114Sscottl struct aac_disk *sc; 16865793Smsmith 16983114Sscottl debug_called(4); 17083114Sscottl 17183114Sscottl sc = (struct aac_disk *)dev->si_drv1; 17265793Smsmith 17383114Sscottl if (sc == NULL) 17483114Sscottl return (ENXIO); 17565793Smsmith 17683114Sscottl sc->ad_flags &= ~AAC_DISK_OPEN; 17783114Sscottl return (0); 17865793Smsmith} 17965793Smsmith 18083114Sscottl/* 18165793Smsmith * Handle an I/O request. 18265793Smsmith */ 18365793Smsmithstatic void 18465793Smsmithaac_disk_strategy(struct bio *bp) 18565793Smsmith{ 18683114Sscottl struct aac_disk *sc; 18765793Smsmith 18883114Sscottl debug_called(4); 18965793Smsmith 19083114Sscottl sc = (struct aac_disk *)bp->bio_dev->si_drv1; 19165793Smsmith 19283114Sscottl /* bogus disk? */ 19383114Sscottl if (sc == NULL) { 19483114Sscottl bp->bio_flags |= BIO_ERROR; 19583114Sscottl bp->bio_error = EINVAL; 19683114Sscottl biodone(bp); 19783114Sscottl return; 19883114Sscottl } 19982527Sscottl 20083114Sscottl /* do-nothing operation? */ 20183114Sscottl if (bp->bio_bcount == 0) { 20283114Sscottl bp->bio_resid = bp->bio_bcount; 20383114Sscottl biodone(bp); 20483114Sscottl return; 20583114Sscottl } 20665793Smsmith 20783114Sscottl /* perform accounting */ 20883114Sscottl devstat_start_transaction(&sc->ad_stats); 20983114Sscottl 21083114Sscottl /* pass the bio to the controller - it can work out who we are */ 21183114Sscottl aac_submit_bio(bp); 21283114Sscottl return; 21365793Smsmith} 21465793Smsmith 21583114Sscottl/* 21695350Sscottl * Map the S/G elements for doing a dump. 21795350Sscottl */ 21895350Sscottlstatic void 21995350Sscottlaac_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 22095350Sscottl{ 22195350Sscottl struct aac_fib *fib; 22295350Sscottl struct aac_blockwrite *bw; 22395350Sscottl struct aac_sg_table *sg; 22495350Sscottl int i; 22595350Sscottl 22695350Sscottl fib = (struct aac_fib *)arg; 22795350Sscottl bw = (struct aac_blockwrite *)&fib->data[0]; 22895350Sscottl sg = &bw->SgMap; 22995350Sscottl 23095350Sscottl if (sg != NULL) { 23195350Sscottl sg->SgCount = nsegs; 23295350Sscottl for (i = 0; i < nsegs; i++) { 23395350Sscottl sg->SgEntry[i].SgAddress = segs[i].ds_addr; 23495350Sscottl sg->SgEntry[i].SgByteCount = segs[i].ds_len; 23595350Sscottl } 23695350Sscottl fib->Header.Size = nsegs * sizeof(struct aac_sg_entry); 23795350Sscottl } 23895350Sscottl} 23995350Sscottl 24095350Sscottl/* 24182527Sscottl * Dump memory out to an array 24282527Sscottl * 24395350Sscottl * Send out one command at a time with up to AAC_MAXIO of data. 24482527Sscottl */ 24582527Sscottlstatic int 24693495Sphkaac_disk_dump(dev_t dev, void *virtual, vm_offset_t physical, off_t offset, size_t length) 24782527Sscottl{ 24883114Sscottl struct aac_disk *ad; 24983114Sscottl struct aac_softc *sc; 25095350Sscottl struct aac_fib *fib; 25195350Sscottl struct aac_blockwrite *bw; 25295350Sscottl size_t len; 25395350Sscottl int size; 25495350Sscottl static bus_dmamap_t dump_datamap; 25595350Sscottl static int first = 0; 25682527Sscottl 25783114Sscottl ad = dev->si_drv1; 25882527Sscottl 25983114Sscottl if (ad == NULL) 26095350Sscottl return (EINVAL); 26182527Sscottl 26283114Sscottl sc= ad->ad_controller; 26382527Sscottl 26495350Sscottl if (!first) { 26595350Sscottl first = 1; 26695350Sscottl if (bus_dmamap_create(sc->aac_buffer_dmat, 0, &dump_datamap)) { 26795350Sscottl printf("bus_dmamap_create failed\n"); 26895350Sscottl return (ENOMEM); 26995350Sscottl } 27095350Sscottl } 27182527Sscottl 27295536Sscottl aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE); 27395350Sscottl bw = (struct aac_blockwrite *)&fib->data[0]; 27482527Sscottl 27595350Sscottl while (length > 0) { 27695350Sscottl len = (length > AAC_MAXIO) ? AAC_MAXIO : length; 27795350Sscottl bw->Command = VM_CtBlockWrite; 27895350Sscottl bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 27995350Sscottl bw->BlockNumber = offset / AAC_BLOCK_SIZE; 28095350Sscottl bw->ByteCount = len; 28195350Sscottl bw->Stable = CUNSTABLE; 28295350Sscottl bus_dmamap_load(sc->aac_buffer_dmat, dump_datamap, virtual, 28395350Sscottl len, aac_dump_map_sg, fib, 0); 28495350Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap, 28595350Sscottl BUS_DMASYNC_PREWRITE); 28682527Sscottl 28795350Sscottl /* fib->Header.Size is set in aac_dump_map_sg */ 28895350Sscottl size = fib->Header.Size + sizeof(struct aac_blockwrite); 28983114Sscottl 29095350Sscottl if (aac_sync_fib(sc, ContainerCommand, 0, fib, size)) { 29195350Sscottl printf("Error dumping block 0x%x\n", physical); 29295350Sscottl return (EIO); 29383114Sscottl } 29495350Sscottl length -= len; 29595350Sscottl offset += len; 29683114Sscottl } 29782527Sscottl 29883114Sscottl return (0); 29982527Sscottl} 30082527Sscottl 30183114Sscottl/* 30265793Smsmith * Handle completion of an I/O request. 30365793Smsmith */ 30465793Smsmithvoid 30570393Smsmithaac_biodone(struct bio *bp) 30665793Smsmith{ 30783114Sscottl struct aac_disk *sc; 30865793Smsmith 30983114Sscottl debug_called(4); 31065793Smsmith 31183114Sscottl sc = (struct aac_disk *)bp->bio_dev->si_drv1; 31283114Sscottl 31383114Sscottl devstat_end_transaction_bio(&sc->ad_stats, bp); 31483114Sscottl if (bp->bio_flags & BIO_ERROR) { 315103675Sphk#if __FreeBSD_version > 500039 316103675Sphk disk_err(bp, "hard error", -1, 1); 317103675Sphk#elif __FreeBSD_version > 500005 318103675Sphk int blkno; 31983114Sscottl blkno = (sc->ad_label.d_nsectors) ? 0 : -1; 32083114Sscottl diskerr(bp, (char *)bp->bio_driver1, blkno, &sc->ad_label); 32182527Sscottl#else 322103675Sphk int blkno; 323103675Sphk blkno = (sc->ad_label.d_nsectors) ? 0 : -1; 32483114Sscottl diskerr(bp, (char *)bp->bio_driver1, 0, blkno, &sc->ad_label); 32582527Sscottl#endif 32683114Sscottl } 32783114Sscottl biodone(bp); 32865793Smsmith} 32965793Smsmith 33083114Sscottl/* 33165793Smsmith * Stub only. 33265793Smsmith */ 33365793Smsmithstatic int 33465793Smsmithaac_disk_probe(device_t dev) 33565793Smsmith{ 33665793Smsmith 33783114Sscottl debug_called(2); 33865793Smsmith 33983114Sscottl return (0); 34065793Smsmith} 34165793Smsmith 34283114Sscottl/* 34365793Smsmith * Attach a unit to the controller. 34465793Smsmith */ 34565793Smsmithstatic int 34665793Smsmithaac_disk_attach(device_t dev) 34765793Smsmith{ 34883114Sscottl struct aac_disk *sc; 34983114Sscottl 35083114Sscottl debug_called(1); 35165793Smsmith 35283114Sscottl sc = (struct aac_disk *)device_get_softc(dev); 35365793Smsmith 35483114Sscottl /* initialise our softc */ 35583114Sscottl sc->ad_controller = 35683114Sscottl (struct aac_softc *)device_get_softc(device_get_parent(dev)); 35783114Sscottl sc->ad_container = device_get_ivars(dev); 35883114Sscottl sc->ad_dev = dev; 35965793Smsmith 36083114Sscottl /* 36183114Sscottl * require that extended translation be enabled - other drivers read the 36283114Sscottl * disk! 36383114Sscottl */ 36483114Sscottl sc->ad_size = sc->ad_container->co_mntobj.Capacity; 36583114Sscottl if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */ 36683114Sscottl sc->ad_heads = 255; 36783114Sscottl sc->ad_sectors = 63; 36883114Sscottl } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */ 36983114Sscottl sc->ad_heads = 128; 37083114Sscottl sc->ad_sectors = 32; 37183114Sscottl } else { 37283114Sscottl sc->ad_heads = 64; 37383114Sscottl sc->ad_sectors = 32; 37483114Sscottl } 37583114Sscottl sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors)); 37665793Smsmith 37783114Sscottl device_printf(dev, "%uMB (%u sectors)\n", 37883114Sscottl sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE), 37983114Sscottl sc->ad_size); 38065793Smsmith 38183114Sscottl devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev), 38283114Sscottl AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS, 38383114Sscottl DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 38483114Sscottl DEVSTAT_PRIORITY_ARRAY); 38583114Sscottl 38683114Sscottl /* attach a generic disk device to ourselves */ 38783114Sscottl sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0, 38883114Sscottl &aac_disk_cdevsw, &aac_disk_disk_cdevsw); 38983114Sscottl sc->ad_dev_t->si_drv1 = sc; 39065793Smsmith#ifdef FREEBSD_4 39183114Sscottl disks_registered++; 39265793Smsmith#endif 39365793Smsmith 39483114Sscottl sc->ad_dev_t->si_iosize_max = aac_iosize_max; 39583114Sscottl sc->unit = device_get_unit(dev); 39681082Sscottl 39783114Sscottl return (0); 39865793Smsmith} 39965793Smsmith 40083114Sscottl/* 40165793Smsmith * Disconnect ourselves from the system. 40265793Smsmith */ 40365793Smsmithstatic int 40465793Smsmithaac_disk_detach(device_t dev) 40565793Smsmith{ 40683114Sscottl struct aac_disk *sc; 40765793Smsmith 40883114Sscottl debug_called(2); 40965793Smsmith 41083114Sscottl sc = (struct aac_disk *)device_get_softc(dev); 41165793Smsmith 41283114Sscottl if (sc->ad_flags & AAC_DISK_OPEN) 41383114Sscottl return(EBUSY); 41483114Sscottl 41583114Sscottl devstat_remove_entry(&sc->ad_stats); 41683114Sscottl disk_destroy(sc->ad_dev_t); 41765793Smsmith#ifdef FREEBSD_4 41883114Sscottl if (--disks_registered == 0) 41983114Sscottl cdevsw_remove(&aac_disk_cdevsw); 42065793Smsmith#endif 42165793Smsmith 42283114Sscottl return(0); 42365793Smsmith} 424