aac_disk.c revision 177899
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 30119418Sobrien#include <sys/cdefs.h> 31119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/aac/aac_disk.c 177899 2008-04-03 23:29:31Z emaste $"); 32119418Sobrien 3381151Sscottl#include "opt_aac.h" 3481151Sscottl 3565793Smsmith#include <sys/param.h> 3665793Smsmith#include <sys/systm.h> 3765793Smsmith#include <sys/kernel.h> 38129879Sphk#include <sys/module.h> 3981154Sscottl#include <sys/sysctl.h> 4065793Smsmith 4165793Smsmith#include <sys/bus.h> 4265793Smsmith#include <sys/conf.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> 53138635Sscottl#include <sys/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 */ 66111525Sscottlstatic disk_open_t aac_disk_open; 67111525Sscottlstatic disk_close_t aac_disk_close; 68111525Sscottlstatic disk_strategy_t aac_disk_strategy; 69111220Sphkstatic dumper_t aac_disk_dump; 7065793Smsmith 7189112Smsmithstatic devclass_t aac_disk_devclass; 7265793Smsmith 7365793Smsmithstatic device_method_t aac_disk_methods[] = { 7483114Sscottl DEVMETHOD(device_probe, aac_disk_probe), 7583114Sscottl DEVMETHOD(device_attach, aac_disk_attach), 7683114Sscottl DEVMETHOD(device_detach, aac_disk_detach), 7783114Sscottl { 0, 0 } 7865793Smsmith}; 7965793Smsmith 8065793Smsmithstatic driver_t aac_disk_driver = { 8183114Sscottl "aacd", 8283114Sscottl aac_disk_methods, 8383114Sscottl sizeof(struct aac_disk) 8465793Smsmith}; 8565793Smsmith 8695350Sscottl#define AAC_MAXIO 65536 8795350Sscottl 8865793SmsmithDRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0); 8965793Smsmith 9081154Sscottl/* sysctl tunables */ 9195350Sscottlstatic unsigned int aac_iosize_max = AAC_MAXIO; /* due to limits of the card */ 9281154SscottlTUNABLE_INT("hw.aac.iosize_max", &aac_iosize_max); 9381154Sscottl 9481154SscottlSYSCTL_DECL(_hw_aac); 95121307SsilbySYSCTL_UINT(_hw_aac, OID_AUTO, iosize_max, CTLFLAG_RDTUN, &aac_iosize_max, 0, 9682527Sscottl "Max I/O size per transfer to an array"); 9781154Sscottl 9883114Sscottl/* 9965793Smsmith * Handle open from generic layer. 10065793Smsmith * 10165793Smsmith * This is called by the diskslice code on first open in order to get the 10265793Smsmith * basic device geometry paramters. 10365793Smsmith */ 10465793Smsmithstatic int 105111525Sscottlaac_disk_open(struct disk *dp) 10665793Smsmith{ 10783114Sscottl struct aac_disk *sc; 10865793Smsmith 109177567Semaste fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 11083114Sscottl 111111525Sscottl sc = (struct aac_disk *)dp->d_drv1; 11265793Smsmith 113109088Sscottl if (sc == NULL) { 114109088Sscottl printf("aac_disk_open: No Softc\n"); 11583114Sscottl return (ENXIO); 116109088Sscottl } 11765793Smsmith 11883114Sscottl /* check that the controller is up and running */ 119109088Sscottl if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND) { 120109088Sscottl printf("Controller Suspended controller state = 0x%x\n", 121109088Sscottl sc->ad_controller->aac_state); 12283114Sscottl return(ENXIO); 123109088Sscottl } 12465793Smsmith 12583114Sscottl sc->ad_flags |= AAC_DISK_OPEN; 12683114Sscottl return (0); 12765793Smsmith} 12865793Smsmith 12983114Sscottl/* 13065793Smsmith * Handle last close of the disk device. 13165793Smsmith */ 13265793Smsmithstatic int 133111525Sscottlaac_disk_close(struct disk *dp) 13465793Smsmith{ 13583114Sscottl struct aac_disk *sc; 13665793Smsmith 137177567Semaste fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 13883114Sscottl 139111525Sscottl sc = (struct aac_disk *)dp->d_drv1; 14065793Smsmith 14183114Sscottl if (sc == NULL) 14283114Sscottl return (ENXIO); 14365793Smsmith 14483114Sscottl sc->ad_flags &= ~AAC_DISK_OPEN; 14583114Sscottl return (0); 14665793Smsmith} 14765793Smsmith 14883114Sscottl/* 14965793Smsmith * Handle an I/O request. 15065793Smsmith */ 15165793Smsmithstatic void 15265793Smsmithaac_disk_strategy(struct bio *bp) 15365793Smsmith{ 15483114Sscottl struct aac_disk *sc; 15565793Smsmith 156111525Sscottl sc = (struct aac_disk *)bp->bio_disk->d_drv1; 157177567Semaste fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 15865793Smsmith 15983114Sscottl /* bogus disk? */ 16083114Sscottl if (sc == NULL) { 16183114Sscottl bp->bio_flags |= BIO_ERROR; 16283114Sscottl bp->bio_error = EINVAL; 16383114Sscottl biodone(bp); 16483114Sscottl return; 16583114Sscottl } 16682527Sscottl 16783114Sscottl /* do-nothing operation? */ 16883114Sscottl if (bp->bio_bcount == 0) { 16983114Sscottl bp->bio_resid = bp->bio_bcount; 17083114Sscottl biodone(bp); 17183114Sscottl return; 17283114Sscottl } 17365793Smsmith 17483114Sscottl /* perform accounting */ 17583114Sscottl 17683114Sscottl /* pass the bio to the controller - it can work out who we are */ 177133540Sscottl mtx_lock(&sc->ad_controller->aac_io_lock); 17883114Sscottl aac_submit_bio(bp); 179133540Sscottl mtx_unlock(&sc->ad_controller->aac_io_lock); 180111532Sscottl 18183114Sscottl return; 18265793Smsmith} 18365793Smsmith 18483114Sscottl/* 18595350Sscottl * Map the S/G elements for doing a dump. 18695350Sscottl */ 18795350Sscottlstatic void 18895350Sscottlaac_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 18995350Sscottl{ 19095350Sscottl struct aac_fib *fib; 19195350Sscottl struct aac_blockwrite *bw; 19295350Sscottl struct aac_sg_table *sg; 19395350Sscottl int i; 19495350Sscottl 19595350Sscottl fib = (struct aac_fib *)arg; 19695350Sscottl bw = (struct aac_blockwrite *)&fib->data[0]; 19795350Sscottl sg = &bw->SgMap; 19895350Sscottl 19995350Sscottl if (sg != NULL) { 20095350Sscottl sg->SgCount = nsegs; 20195350Sscottl for (i = 0; i < nsegs; i++) { 202116553Sscottl if (segs[i].ds_addr >= BUS_SPACE_MAXADDR_32BIT) 203116553Sscottl return; 20495350Sscottl sg->SgEntry[i].SgAddress = segs[i].ds_addr; 20595350Sscottl sg->SgEntry[i].SgByteCount = segs[i].ds_len; 20695350Sscottl } 20795350Sscottl fib->Header.Size = nsegs * sizeof(struct aac_sg_entry); 20895350Sscottl } 20995350Sscottl} 21095350Sscottl 21195350Sscottl/* 212177899Semaste * Map the S/G elements for doing a dump on 64-bit capable devices. 213177899Semaste */ 214177899Semastestatic void 215177899Semasteaac_dump_map_sg64(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 216177899Semaste{ 217177899Semaste struct aac_fib *fib; 218177899Semaste struct aac_blockwrite64 *bw; 219177899Semaste struct aac_sg_table64 *sg; 220177899Semaste int i; 221177899Semaste 222177899Semaste fib = (struct aac_fib *)arg; 223177899Semaste bw = (struct aac_blockwrite64 *)&fib->data[0]; 224177899Semaste sg = &bw->SgMap64; 225177899Semaste 226177899Semaste if (sg != NULL) { 227177899Semaste sg->SgCount = nsegs; 228177899Semaste for (i = 0; i < nsegs; i++) { 229177899Semaste sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 230177899Semaste sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 231177899Semaste } 232177899Semaste fib->Header.Size = nsegs * sizeof(struct aac_sg_entry64); 233177899Semaste } 234177899Semaste} 235177899Semaste 236177899Semaste/* 23782527Sscottl * Dump memory out to an array 23882527Sscottl * 23995350Sscottl * Send out one command at a time with up to AAC_MAXIO of data. 24082527Sscottl */ 24182527Sscottlstatic int 242111220Sphkaac_disk_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 24382527Sscottl{ 24483114Sscottl struct aac_disk *ad; 24583114Sscottl struct aac_softc *sc; 24695350Sscottl struct aac_fib *fib; 24795350Sscottl size_t len; 24895350Sscottl int size; 24995350Sscottl static bus_dmamap_t dump_datamap; 25095350Sscottl static int first = 0; 251111220Sphk struct disk *dp; 252177899Semaste bus_dmamap_callback_t *callback; 253177899Semaste u_int32_t command; 25482527Sscottl 255111220Sphk dp = arg; 256111525Sscottl ad = dp->d_drv1; 25782527Sscottl 25883114Sscottl if (ad == NULL) 25995350Sscottl return (EINVAL); 26082527Sscottl 26183114Sscottl sc= ad->ad_controller; 26282527Sscottl 26395350Sscottl if (!first) { 26495350Sscottl first = 1; 26595350Sscottl if (bus_dmamap_create(sc->aac_buffer_dmat, 0, &dump_datamap)) { 26695350Sscottl printf("bus_dmamap_create failed\n"); 26795350Sscottl return (ENOMEM); 26895350Sscottl } 26995350Sscottl } 27082527Sscottl 271130006Sscottl /* Skip aac_alloc_sync_fib(). We don't want to mess with sleep locks */ 272130006Sscottl fib = &sc->aac_common->ac_sync_fib; 27382527Sscottl 27495350Sscottl while (length > 0) { 27595350Sscottl len = (length > AAC_MAXIO) ? AAC_MAXIO : length; 276177899Semaste if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 277177899Semaste struct aac_blockwrite *bw; 278177899Semaste bw = (struct aac_blockwrite *)&fib->data[0]; 279177899Semaste bw->Command = VM_CtBlockWrite; 280177899Semaste bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 281177899Semaste bw->BlockNumber = offset / AAC_BLOCK_SIZE; 282177899Semaste bw->ByteCount = len; 283177899Semaste bw->Stable = CUNSTABLE; 284177899Semaste command = ContainerCommand; 285177899Semaste callback = aac_dump_map_sg; 286177899Semaste size = sizeof(struct aac_blockwrite); 287177899Semaste } else { 288177899Semaste struct aac_blockwrite64 *bw; 289177899Semaste bw = (struct aac_blockwrite64 *)&fib->data[0]; 290177899Semaste bw->Command = VM_CtHostWrite64; 291177899Semaste bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 292177899Semaste bw->BlockNumber = offset / AAC_BLOCK_SIZE; 293177899Semaste bw->SectorCount = len / AAC_BLOCK_SIZE; 294177899Semaste bw->Pad = 0; 295177899Semaste bw->Flags = 0; 296177899Semaste command = ContainerCommand64; 297177899Semaste callback = aac_dump_map_sg64; 298177899Semaste size = sizeof(struct aac_blockwrite64); 299177899Semaste } 300116553Sscottl 301116553Sscottl /* 302116553Sscottl * There really isn't any way to recover from errors or 303116553Sscottl * resource shortages here. Oh well. Because of that, don't 304116553Sscottl * bother trying to send the command from the callback; there 305116553Sscottl * is too much required context. 306116553Sscottl */ 307116553Sscottl if (bus_dmamap_load(sc->aac_buffer_dmat, dump_datamap, virtual, 308177899Semaste len, callback, fib, BUS_DMA_NOWAIT) != 0) 309145811Sscottl return (ENOMEM); 310116553Sscottl 31195350Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap, 31295350Sscottl BUS_DMASYNC_PREWRITE); 31382527Sscottl 31495350Sscottl /* fib->Header.Size is set in aac_dump_map_sg */ 315177899Semaste size += fib->Header.Size; 31683114Sscottl 317177899Semaste if (aac_sync_fib(sc, command, 0, fib, size)) { 318119146Sscottl printf("Error dumping block 0x%jx\n", 319119171Smux (uintmax_t)physical); 32095350Sscottl return (EIO); 32183114Sscottl } 322116553Sscottl 323145811Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap, 324145811Sscottl BUS_DMASYNC_POSTWRITE); 325145811Sscottl 326145811Sscottl bus_dmamap_unload(sc->aac_buffer_dmat, dump_datamap); 327145811Sscottl 32895350Sscottl length -= len; 32995350Sscottl offset += len; 330132771Skan virtual = (uint8_t *)virtual + len; 33183114Sscottl } 33282527Sscottl 33383114Sscottl return (0); 33482527Sscottl} 33582527Sscottl 33683114Sscottl/* 33765793Smsmith * Handle completion of an I/O request. 33865793Smsmith */ 33965793Smsmithvoid 34070393Smsmithaac_biodone(struct bio *bp) 34165793Smsmith{ 34283114Sscottl struct aac_disk *sc; 34365793Smsmith 344111525Sscottl sc = (struct aac_disk *)bp->bio_disk->d_drv1; 345177567Semaste fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 34683114Sscottl 347111691Sscottl if (bp->bio_flags & BIO_ERROR) 348103675Sphk disk_err(bp, "hard error", -1, 1); 349111691Sscottl 35083114Sscottl biodone(bp); 35165793Smsmith} 35265793Smsmith 35383114Sscottl/* 35465793Smsmith * Stub only. 35565793Smsmith */ 35665793Smsmithstatic int 35765793Smsmithaac_disk_probe(device_t dev) 35865793Smsmith{ 35965793Smsmith 360177567Semaste fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 36165793Smsmith 36283114Sscottl return (0); 36365793Smsmith} 36465793Smsmith 36583114Sscottl/* 36665793Smsmith * Attach a unit to the controller. 36765793Smsmith */ 36865793Smsmithstatic int 36965793Smsmithaac_disk_attach(device_t dev) 37065793Smsmith{ 37183114Sscottl struct aac_disk *sc; 37283114Sscottl 37383114Sscottl sc = (struct aac_disk *)device_get_softc(dev); 374177567Semaste fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 37565793Smsmith 37683114Sscottl /* initialise our softc */ 37783114Sscottl sc->ad_controller = 37883114Sscottl (struct aac_softc *)device_get_softc(device_get_parent(dev)); 37983114Sscottl sc->ad_container = device_get_ivars(dev); 38083114Sscottl sc->ad_dev = dev; 38165793Smsmith 38283114Sscottl /* 38383114Sscottl * require that extended translation be enabled - other drivers read the 38483114Sscottl * disk! 38583114Sscottl */ 38683114Sscottl sc->ad_size = sc->ad_container->co_mntobj.Capacity; 387177619Semaste if (sc->ad_controller->flags & AAC_FLAGS_LBA_64BIT) 388177619Semaste sc->ad_size += (u_int64_t) 389177619Semaste sc->ad_container->co_mntobj.CapacityHigh << 32; 39083114Sscottl if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */ 39183114Sscottl sc->ad_heads = 255; 39283114Sscottl sc->ad_sectors = 63; 39383114Sscottl } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */ 39483114Sscottl sc->ad_heads = 128; 39583114Sscottl sc->ad_sectors = 32; 39683114Sscottl } else { 39783114Sscottl sc->ad_heads = 64; 39883114Sscottl sc->ad_sectors = 32; 39983114Sscottl } 40083114Sscottl sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors)); 40165793Smsmith 402177619Semaste device_printf(dev, "%juMB (%ju sectors)\n", 403177619Semaste (intmax_t)sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE), 404177619Semaste (intmax_t)sc->ad_size); 40565793Smsmith 40683114Sscottl /* attach a generic disk device to ourselves */ 40783114Sscottl sc->unit = device_get_unit(dev); 408125975Sphk sc->ad_disk = disk_alloc(); 409125975Sphk sc->ad_disk->d_drv1 = sc; 410125975Sphk sc->ad_disk->d_name = "aacd"; 411125975Sphk sc->ad_disk->d_maxsize = aac_iosize_max; 412125975Sphk sc->ad_disk->d_open = aac_disk_open; 413125975Sphk sc->ad_disk->d_close = aac_disk_close; 414125975Sphk sc->ad_disk->d_strategy = aac_disk_strategy; 415125975Sphk sc->ad_disk->d_dump = aac_disk_dump; 416125975Sphk sc->ad_disk->d_sectorsize = AAC_BLOCK_SIZE; 417125975Sphk sc->ad_disk->d_mediasize = (off_t)sc->ad_size * AAC_BLOCK_SIZE; 418125975Sphk sc->ad_disk->d_fwsectors = sc->ad_sectors; 419125975Sphk sc->ad_disk->d_fwheads = sc->ad_heads; 420125975Sphk sc->ad_disk->d_unit = sc->unit; 421125975Sphk disk_create(sc->ad_disk, DISK_VERSION); 42281082Sscottl 42383114Sscottl return (0); 42465793Smsmith} 42565793Smsmith 42683114Sscottl/* 42765793Smsmith * Disconnect ourselves from the system. 42865793Smsmith */ 42965793Smsmithstatic int 43065793Smsmithaac_disk_detach(device_t dev) 43165793Smsmith{ 43283114Sscottl struct aac_disk *sc; 43365793Smsmith 43483114Sscottl sc = (struct aac_disk *)device_get_softc(dev); 435177567Semaste fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 43665793Smsmith 43783114Sscottl if (sc->ad_flags & AAC_DISK_OPEN) 43883114Sscottl return(EBUSY); 43983114Sscottl 440125975Sphk disk_destroy(sc->ad_disk); 44165793Smsmith 44283114Sscottl return(0); 44365793Smsmith} 444