1942c5e3cSpl196000 /* 2*3fced439Szhongyan gu - Sun Microsystems - Beijing China * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 3942c5e3cSpl196000 */ 4942c5e3cSpl196000 5942c5e3cSpl196000 /* 6942c5e3cSpl196000 * Copyright 2005-06 Adaptec, Inc. 7942c5e3cSpl196000 * Copyright (c) 2005-06 Adaptec Inc., Achim Leubner 8942c5e3cSpl196000 * Copyright (c) 2000 Michael Smith 9942c5e3cSpl196000 * Copyright (c) 2001 Scott Long 10942c5e3cSpl196000 * Copyright (c) 2000 BSDi 11942c5e3cSpl196000 * All rights reserved. 12942c5e3cSpl196000 * 13942c5e3cSpl196000 * Redistribution and use in source and binary forms, with or without 14942c5e3cSpl196000 * modification, are permitted provided that the following conditions 15942c5e3cSpl196000 * are met: 16942c5e3cSpl196000 * 1. Redistributions of source code must retain the above copyright 17942c5e3cSpl196000 * notice, this list of conditions and the following disclaimer. 18942c5e3cSpl196000 * 2. Redistributions in binary form must reproduce the above copyright 19942c5e3cSpl196000 * notice, this list of conditions and the following disclaimer in the 20942c5e3cSpl196000 * documentation and/or other materials provided with the distribution. 21942c5e3cSpl196000 * 22942c5e3cSpl196000 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23942c5e3cSpl196000 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24942c5e3cSpl196000 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25942c5e3cSpl196000 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26942c5e3cSpl196000 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27942c5e3cSpl196000 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28942c5e3cSpl196000 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29942c5e3cSpl196000 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30942c5e3cSpl196000 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31942c5e3cSpl196000 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32942c5e3cSpl196000 * SUCH DAMAGE. 33942c5e3cSpl196000 */ 34942c5e3cSpl196000 #include <sys/modctl.h> 35942c5e3cSpl196000 #include <sys/conf.h> 36942c5e3cSpl196000 #include <sys/cmn_err.h> 37942c5e3cSpl196000 #include <sys/ddi.h> 38942c5e3cSpl196000 #include <sys/devops.h> 39942c5e3cSpl196000 #include <sys/pci.h> 40942c5e3cSpl196000 #include <sys/types.h> 41942c5e3cSpl196000 #include <sys/ddidmareq.h> 42942c5e3cSpl196000 #include <sys/scsi/scsi.h> 43942c5e3cSpl196000 #include <sys/ksynch.h> 44942c5e3cSpl196000 #include <sys/sunddi.h> 45942c5e3cSpl196000 #include <sys/byteorder.h> 46942c5e3cSpl196000 #include <sys/kmem.h> 47942c5e3cSpl196000 #include "aac_regs.h" 48942c5e3cSpl196000 #include "aac.h" 49942c5e3cSpl196000 #include "aac_ioctl.h" 50942c5e3cSpl196000 51942c5e3cSpl196000 struct aac_umem_sge { 52942c5e3cSpl196000 uint32_t bcount; 53942c5e3cSpl196000 caddr_t addr; 54942c5e3cSpl196000 struct aac_cmd acp; 55942c5e3cSpl196000 }; 56942c5e3cSpl196000 57942c5e3cSpl196000 /* 58942c5e3cSpl196000 * External functions 59942c5e3cSpl196000 */ 60942c5e3cSpl196000 extern int aac_sync_mbcommand(struct aac_softstate *, uint32_t, uint32_t, 61942c5e3cSpl196000 uint32_t, uint32_t, uint32_t, uint32_t *); 62942c5e3cSpl196000 extern int aac_cmd_dma_alloc(struct aac_softstate *, struct aac_cmd *, 63942c5e3cSpl196000 struct buf *, int, int (*)(), caddr_t); 64942c5e3cSpl196000 extern void aac_free_dmamap(struct aac_cmd *); 65942c5e3cSpl196000 extern int aac_do_io(struct aac_softstate *, struct aac_cmd *); 66942c5e3cSpl196000 extern void aac_cmd_fib_copy(struct aac_softstate *, struct aac_cmd *); 67942c5e3cSpl196000 extern void aac_ioctl_complete(struct aac_softstate *, struct aac_cmd *); 680749e8deSXin Chen - Sun Microsystems - Beijing China extern int aac_return_aif_wait(struct aac_softstate *, struct aac_fib_context *, 690749e8deSXin Chen - Sun Microsystems - Beijing China struct aac_fib **); 700749e8deSXin Chen - Sun Microsystems - Beijing China extern int aac_return_aif(struct aac_softstate *, struct aac_fib_context *, 710749e8deSXin Chen - Sun Microsystems - Beijing China struct aac_fib **); 72942c5e3cSpl196000 73942c5e3cSpl196000 extern ddi_device_acc_attr_t aac_acc_attr; 74942c5e3cSpl196000 extern int aac_check_dma_handle(ddi_dma_handle_t); 75942c5e3cSpl196000 76942c5e3cSpl196000 /* 77942c5e3cSpl196000 * IOCTL command handling functions 78942c5e3cSpl196000 */ 79942c5e3cSpl196000 static int aac_check_revision(struct aac_softstate *, intptr_t, int); 80942c5e3cSpl196000 static int aac_ioctl_send_fib(struct aac_softstate *, intptr_t, int); 81942c5e3cSpl196000 static int aac_open_getadapter_fib(struct aac_softstate *, intptr_t, int); 82942c5e3cSpl196000 static int aac_next_getadapter_fib(struct aac_softstate *, intptr_t, int); 83942c5e3cSpl196000 static int aac_close_getadapter_fib(struct aac_softstate *, intptr_t); 84942c5e3cSpl196000 static int aac_send_raw_srb(struct aac_softstate *, dev_t, intptr_t, int); 85942c5e3cSpl196000 static int aac_get_pci_info(struct aac_softstate *, intptr_t, int); 86942c5e3cSpl196000 static int aac_query_disk(struct aac_softstate *, intptr_t, int); 87942c5e3cSpl196000 static int aac_delete_disk(struct aac_softstate *, intptr_t, int); 88942c5e3cSpl196000 static int aac_supported_features(struct aac_softstate *, intptr_t, int); 89942c5e3cSpl196000 90942c5e3cSpl196000 /* 91942c5e3cSpl196000 * Warlock directives 92942c5e3cSpl196000 */ 93942c5e3cSpl196000 _NOTE(SCHEME_PROTECTS_DATA("unique to each handling function", aac_features 94942c5e3cSpl196000 aac_pci_info aac_query_disk aac_revision aac_umem_sge)) 95942c5e3cSpl196000 96942c5e3cSpl196000 int 97942c5e3cSpl196000 aac_do_ioctl(struct aac_softstate *softs, dev_t dev, int cmd, intptr_t arg, 98942c5e3cSpl196000 int mode) 99942c5e3cSpl196000 { 100942c5e3cSpl196000 int status; 101942c5e3cSpl196000 102942c5e3cSpl196000 switch (cmd) { 103942c5e3cSpl196000 case FSACTL_MINIPORT_REV_CHECK: 104942c5e3cSpl196000 AACDB_PRINT_IOCTL(softs, "FSACTL_MINIPORT_REV_CHECK"); 105942c5e3cSpl196000 status = aac_check_revision(softs, arg, mode); 106942c5e3cSpl196000 break; 107942c5e3cSpl196000 case FSACTL_SENDFIB: 108942c5e3cSpl196000 AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_LARGE_FIB"); 109942c5e3cSpl196000 goto send_fib; 110942c5e3cSpl196000 case FSACTL_SEND_LARGE_FIB: 111942c5e3cSpl196000 AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_LARGE_FIB"); 112942c5e3cSpl196000 send_fib: 113942c5e3cSpl196000 status = aac_ioctl_send_fib(softs, arg, mode); 114942c5e3cSpl196000 break; 115942c5e3cSpl196000 case FSACTL_OPEN_GET_ADAPTER_FIB: 116942c5e3cSpl196000 AACDB_PRINT_IOCTL(softs, "FSACTL_OPEN_GET_ADAPTER_FIB"); 117942c5e3cSpl196000 status = aac_open_getadapter_fib(softs, arg, mode); 118942c5e3cSpl196000 break; 119942c5e3cSpl196000 case FSACTL_GET_NEXT_ADAPTER_FIB: 120942c5e3cSpl196000 AACDB_PRINT_IOCTL(softs, "FSACTL_GET_NEXT_ADAPTER_FIB"); 121942c5e3cSpl196000 status = aac_next_getadapter_fib(softs, arg, mode); 122942c5e3cSpl196000 break; 123942c5e3cSpl196000 case FSACTL_CLOSE_GET_ADAPTER_FIB: 124942c5e3cSpl196000 AACDB_PRINT_IOCTL(softs, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 125942c5e3cSpl196000 status = aac_close_getadapter_fib(softs, arg); 126942c5e3cSpl196000 break; 127942c5e3cSpl196000 case FSACTL_SEND_RAW_SRB: 128942c5e3cSpl196000 AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_RAW_SRB"); 129942c5e3cSpl196000 status = aac_send_raw_srb(softs, dev, arg, mode); 130942c5e3cSpl196000 break; 131942c5e3cSpl196000 case FSACTL_GET_PCI_INFO: 132942c5e3cSpl196000 AACDB_PRINT_IOCTL(softs, "FSACTL_GET_PCI_INFO"); 133942c5e3cSpl196000 status = aac_get_pci_info(softs, arg, mode); 134942c5e3cSpl196000 break; 135942c5e3cSpl196000 case FSACTL_QUERY_DISK: 136942c5e3cSpl196000 AACDB_PRINT_IOCTL(softs, "FSACTL_QUERY_DISK"); 137942c5e3cSpl196000 status = aac_query_disk(softs, arg, mode); 138942c5e3cSpl196000 break; 139942c5e3cSpl196000 case FSACTL_DELETE_DISK: 140942c5e3cSpl196000 AACDB_PRINT_IOCTL(softs, "FSACTL_DELETE_DISK"); 141942c5e3cSpl196000 status = aac_delete_disk(softs, arg, mode); 142942c5e3cSpl196000 break; 143942c5e3cSpl196000 case FSACTL_GET_FEATURES: 144942c5e3cSpl196000 AACDB_PRINT_IOCTL(softs, "FSACTL_GET_FEATURES"); 145942c5e3cSpl196000 status = aac_supported_features(softs, arg, mode); 146942c5e3cSpl196000 break; 147942c5e3cSpl196000 default: 148942c5e3cSpl196000 status = ENOTTY; 149942c5e3cSpl196000 AACDB_PRINT(softs, CE_WARN, 150942c5e3cSpl196000 "!IOCTL cmd 0x%x not supported", cmd); 151942c5e3cSpl196000 break; 152942c5e3cSpl196000 } 153942c5e3cSpl196000 154942c5e3cSpl196000 return (status); 155942c5e3cSpl196000 } 156942c5e3cSpl196000 157942c5e3cSpl196000 /*ARGSUSED*/ 158942c5e3cSpl196000 static int 159942c5e3cSpl196000 aac_check_revision(struct aac_softstate *softs, intptr_t arg, int mode) 160942c5e3cSpl196000 { 161942c5e3cSpl196000 union aac_revision_align un; 162942c5e3cSpl196000 struct aac_revision *aac_rev = &un.d; 163942c5e3cSpl196000 164942c5e3cSpl196000 DBCALLED(softs, 2); 165942c5e3cSpl196000 166942c5e3cSpl196000 /* Copyin the revision struct from userspace */ 167942c5e3cSpl196000 if (ddi_copyin((void *)arg, aac_rev, 168942c5e3cSpl196000 sizeof (struct aac_revision), mode) != 0) 169942c5e3cSpl196000 return (EFAULT); 170942c5e3cSpl196000 171942c5e3cSpl196000 /* Doctor up the response struct */ 172942c5e3cSpl196000 aac_rev->compat = 1; 173942c5e3cSpl196000 aac_rev->version = 174942c5e3cSpl196000 ((uint32_t)AAC_DRIVER_MAJOR_VERSION << 24) | 175942c5e3cSpl196000 ((uint32_t)AAC_DRIVER_MINOR_VERSION << 16) | 176942c5e3cSpl196000 ((uint32_t)AAC_DRIVER_TYPE << 8) | 177942c5e3cSpl196000 ((uint32_t)AAC_DRIVER_BUGFIX_LEVEL); 178942c5e3cSpl196000 aac_rev->build = (uint32_t)AAC_DRIVER_BUILD; 179942c5e3cSpl196000 180942c5e3cSpl196000 if (ddi_copyout(aac_rev, (void *)arg, 181942c5e3cSpl196000 sizeof (struct aac_revision), mode) != 0) 182942c5e3cSpl196000 return (EFAULT); 183942c5e3cSpl196000 184942c5e3cSpl196000 return (0); 185942c5e3cSpl196000 } 186942c5e3cSpl196000 187942c5e3cSpl196000 static int 188942c5e3cSpl196000 aac_send_fib(struct aac_softstate *softs, struct aac_cmd *acp) 189942c5e3cSpl196000 { 190942c5e3cSpl196000 int rval; 191942c5e3cSpl196000 192942c5e3cSpl196000 acp->flags |= AAC_CMD_NO_CB | AAC_CMD_SYNC; 193942c5e3cSpl196000 acp->ac_comp = aac_ioctl_complete; 194942c5e3cSpl196000 195942c5e3cSpl196000 mutex_enter(&softs->io_lock); 196942c5e3cSpl196000 if (softs->state & AAC_STATE_DEAD) { 197942c5e3cSpl196000 mutex_exit(&softs->io_lock); 198942c5e3cSpl196000 return (ENXIO); 199942c5e3cSpl196000 } 200942c5e3cSpl196000 201942c5e3cSpl196000 rval = aac_do_io(softs, acp); 202942c5e3cSpl196000 if (rval == TRAN_ACCEPT) { 203942c5e3cSpl196000 rval = 0; 204942c5e3cSpl196000 } else if (rval == TRAN_BADPKT) { 205942c5e3cSpl196000 AACDB_PRINT(softs, CE_CONT, "User SendFib failed ENXIO"); 206942c5e3cSpl196000 rval = ENXIO; 207942c5e3cSpl196000 } else if (rval == TRAN_BUSY) { 208942c5e3cSpl196000 AACDB_PRINT(softs, CE_CONT, "User SendFib failed EBUSY"); 209942c5e3cSpl196000 rval = EBUSY; 210942c5e3cSpl196000 } 211942c5e3cSpl196000 mutex_exit(&softs->io_lock); 212942c5e3cSpl196000 213942c5e3cSpl196000 return (rval); 214942c5e3cSpl196000 } 215942c5e3cSpl196000 216942c5e3cSpl196000 static int 217942c5e3cSpl196000 aac_ioctl_send_fib(struct aac_softstate *softs, intptr_t arg, int mode) 218942c5e3cSpl196000 { 219942c5e3cSpl196000 int hbalen; 220942c5e3cSpl196000 struct aac_cmd *acp; 221942c5e3cSpl196000 struct aac_fib *fibp; 222942c5e3cSpl196000 uint16_t fib_command; 223942c5e3cSpl196000 uint32_t fib_xfer_state; 224942c5e3cSpl196000 uint16_t fib_data_size, fib_size; 225942c5e3cSpl196000 uint16_t fib_sender_size; 226942c5e3cSpl196000 int rval; 227942c5e3cSpl196000 228942c5e3cSpl196000 DBCALLED(softs, 2); 229942c5e3cSpl196000 230942c5e3cSpl196000 /* Copy in FIB header */ 231942c5e3cSpl196000 hbalen = sizeof (struct aac_cmd) + softs->aac_max_fib_size; 232942c5e3cSpl196000 if ((acp = kmem_zalloc(hbalen, KM_NOSLEEP)) == NULL) 233942c5e3cSpl196000 return (ENOMEM); 234942c5e3cSpl196000 235942c5e3cSpl196000 fibp = (struct aac_fib *)(acp + 1); 236942c5e3cSpl196000 acp->fibp = fibp; 237942c5e3cSpl196000 if (ddi_copyin((void *)arg, fibp, 238942c5e3cSpl196000 sizeof (struct aac_fib_header), mode) != 0) { 239942c5e3cSpl196000 rval = EFAULT; 240942c5e3cSpl196000 goto finish; 241942c5e3cSpl196000 } 242942c5e3cSpl196000 243942c5e3cSpl196000 fib_xfer_state = LE_32(fibp->Header.XferState); 244942c5e3cSpl196000 fib_command = LE_16(fibp->Header.Command); 245942c5e3cSpl196000 fib_data_size = LE_16(fibp->Header.Size); 246942c5e3cSpl196000 fib_sender_size = LE_16(fibp->Header.SenderSize); 247942c5e3cSpl196000 248942c5e3cSpl196000 fib_size = fib_data_size + sizeof (struct aac_fib_header); 249942c5e3cSpl196000 if (fib_size < fib_sender_size) 250942c5e3cSpl196000 fib_size = fib_sender_size; 251942c5e3cSpl196000 if (fib_size > softs->aac_max_fib_size) { 252942c5e3cSpl196000 rval = EFAULT; 253942c5e3cSpl196000 goto finish; 254942c5e3cSpl196000 } 255942c5e3cSpl196000 256942c5e3cSpl196000 /* Copy in FIB data */ 257942c5e3cSpl196000 if (ddi_copyin(((struct aac_fib *)arg)->data, fibp->data, 258942c5e3cSpl196000 fib_data_size, mode) != 0) { 259942c5e3cSpl196000 rval = EFAULT; 260942c5e3cSpl196000 goto finish; 261942c5e3cSpl196000 } 262942c5e3cSpl196000 acp->fib_size = fib_size; 263942c5e3cSpl196000 fibp->Header.Size = LE_16(fib_size); 264942c5e3cSpl196000 265942c5e3cSpl196000 /* Process FIB */ 266942c5e3cSpl196000 if (fib_command == TakeABreakPt) { 26758bc78c7SXin Chen #ifdef DEBUG 26858bc78c7SXin Chen if (aac_dbflag_on(softs, AACDB_FLAGS_FIB) && 26958bc78c7SXin Chen (softs->debug_fib_flags & AACDB_FLAGS_FIB_IOCTL)) 27058bc78c7SXin Chen aac_printf(softs, CE_NOTE, "FIB> TakeABreakPt, sz=%d", 27158bc78c7SXin Chen fib_size); 27258bc78c7SXin Chen #endif 273942c5e3cSpl196000 (void) aac_sync_mbcommand(softs, AAC_BREAKPOINT_REQ, 274942c5e3cSpl196000 0, 0, 0, 0, NULL); 275942c5e3cSpl196000 fibp->Header.XferState = LE_32(0); 276942c5e3cSpl196000 } else { 277942c5e3cSpl196000 ASSERT(!(fib_xfer_state & AAC_FIBSTATE_ASYNC)); 278942c5e3cSpl196000 fibp->Header.XferState = LE_32(fib_xfer_state | \ 279942c5e3cSpl196000 (AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_REXPECTED)); 280942c5e3cSpl196000 281942c5e3cSpl196000 acp->timeout = AAC_IOCTL_TIMEOUT; 282942c5e3cSpl196000 acp->aac_cmd_fib = aac_cmd_fib_copy; 28358bc78c7SXin Chen #ifdef DEBUG 28458bc78c7SXin Chen acp->fib_flags = AACDB_FLAGS_FIB_IOCTL; 28558bc78c7SXin Chen #endif 286942c5e3cSpl196000 if ((rval = aac_send_fib(softs, acp)) != 0) 287942c5e3cSpl196000 goto finish; 288942c5e3cSpl196000 } 289942c5e3cSpl196000 290942c5e3cSpl196000 if (acp->flags & AAC_CMD_ERR) { 291942c5e3cSpl196000 AACDB_PRINT(softs, CE_CONT, "FIB data corrupt"); 292942c5e3cSpl196000 rval = EIO; 293942c5e3cSpl196000 goto finish; 294942c5e3cSpl196000 } 295942c5e3cSpl196000 296942c5e3cSpl196000 if (ddi_copyout(fibp, (void *)arg, acp->fib_size, mode) != 0) { 297942c5e3cSpl196000 AACDB_PRINT(softs, CE_CONT, "FIB copyout failed"); 298942c5e3cSpl196000 rval = EFAULT; 299942c5e3cSpl196000 goto finish; 300942c5e3cSpl196000 } 301942c5e3cSpl196000 302942c5e3cSpl196000 rval = 0; 303942c5e3cSpl196000 finish: 304942c5e3cSpl196000 kmem_free(acp, hbalen); 305942c5e3cSpl196000 return (rval); 306942c5e3cSpl196000 } 307942c5e3cSpl196000 308942c5e3cSpl196000 static int 309942c5e3cSpl196000 aac_open_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode) 310942c5e3cSpl196000 { 3110749e8deSXin Chen - Sun Microsystems - Beijing China struct aac_fib_context *fibctx_p, *ctx_p; 312942c5e3cSpl196000 313942c5e3cSpl196000 DBCALLED(softs, 2); 314942c5e3cSpl196000 3150749e8deSXin Chen - Sun Microsystems - Beijing China fibctx_p = kmem_zalloc(sizeof (struct aac_fib_context), KM_NOSLEEP); 3160749e8deSXin Chen - Sun Microsystems - Beijing China if (fibctx_p == NULL) 317942c5e3cSpl196000 return (ENOMEM); 318942c5e3cSpl196000 319942c5e3cSpl196000 mutex_enter(&softs->aifq_mutex); 320942c5e3cSpl196000 /* All elements are already 0, add to queue */ 3210749e8deSXin Chen - Sun Microsystems - Beijing China if (softs->fibctx_p == NULL) { 3220749e8deSXin Chen - Sun Microsystems - Beijing China softs->fibctx_p = fibctx_p; 323942c5e3cSpl196000 } else { 3240749e8deSXin Chen - Sun Microsystems - Beijing China for (ctx_p = softs->fibctx_p; ctx_p->next; ctx_p = ctx_p->next) 325942c5e3cSpl196000 ; 3260749e8deSXin Chen - Sun Microsystems - Beijing China ctx_p->next = fibctx_p; 3270749e8deSXin Chen - Sun Microsystems - Beijing China fibctx_p->prev = ctx_p; 328942c5e3cSpl196000 } 329942c5e3cSpl196000 330942c5e3cSpl196000 /* Evaluate unique value */ 3310749e8deSXin Chen - Sun Microsystems - Beijing China fibctx_p->unique = (unsigned long)fibctx_p & 0xfffffffful; 3320749e8deSXin Chen - Sun Microsystems - Beijing China ctx_p = softs->fibctx_p; 3330749e8deSXin Chen - Sun Microsystems - Beijing China while (ctx_p != fibctx_p) { 3340749e8deSXin Chen - Sun Microsystems - Beijing China if (ctx_p->unique == fibctx_p->unique) { 3350749e8deSXin Chen - Sun Microsystems - Beijing China fibctx_p->unique++; 3360749e8deSXin Chen - Sun Microsystems - Beijing China ctx_p = softs->fibctx_p; 337942c5e3cSpl196000 } else { 3380749e8deSXin Chen - Sun Microsystems - Beijing China ctx_p = ctx_p->next; 339942c5e3cSpl196000 } 340942c5e3cSpl196000 } 341942c5e3cSpl196000 342942c5e3cSpl196000 /* Set ctx_idx to the oldest AIF */ 343942c5e3cSpl196000 if (softs->aifq_wrap) { 3440749e8deSXin Chen - Sun Microsystems - Beijing China fibctx_p->ctx_idx = softs->aifq_idx; 3450749e8deSXin Chen - Sun Microsystems - Beijing China fibctx_p->ctx_filled = 1; 346942c5e3cSpl196000 } 347942c5e3cSpl196000 mutex_exit(&softs->aifq_mutex); 348942c5e3cSpl196000 3490749e8deSXin Chen - Sun Microsystems - Beijing China if (ddi_copyout(&fibctx_p->unique, (void *)arg, 350942c5e3cSpl196000 sizeof (uint32_t), mode) != 0) 351942c5e3cSpl196000 return (EFAULT); 352942c5e3cSpl196000 353942c5e3cSpl196000 return (0); 354942c5e3cSpl196000 } 355942c5e3cSpl196000 356942c5e3cSpl196000 static int 357942c5e3cSpl196000 aac_next_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode) 358942c5e3cSpl196000 { 359942c5e3cSpl196000 union aac_get_adapter_fib_align un; 360942c5e3cSpl196000 struct aac_get_adapter_fib *af = &un.d; 3610749e8deSXin Chen - Sun Microsystems - Beijing China struct aac_fib_context *ctx_p; 3620749e8deSXin Chen - Sun Microsystems - Beijing China struct aac_fib *fibp; 363942c5e3cSpl196000 int rval; 364942c5e3cSpl196000 365942c5e3cSpl196000 DBCALLED(softs, 2); 366942c5e3cSpl196000 367942c5e3cSpl196000 if (ddi_copyin((void *)arg, af, sizeof (*af), mode) != 0) 368942c5e3cSpl196000 return (EFAULT); 369942c5e3cSpl196000 370942c5e3cSpl196000 mutex_enter(&softs->aifq_mutex); 3710749e8deSXin Chen - Sun Microsystems - Beijing China for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) { 3720749e8deSXin Chen - Sun Microsystems - Beijing China if (af->context == ctx_p->unique) 373942c5e3cSpl196000 break; 374942c5e3cSpl196000 } 375942c5e3cSpl196000 mutex_exit(&softs->aifq_mutex); 376942c5e3cSpl196000 3770749e8deSXin Chen - Sun Microsystems - Beijing China if (ctx_p) { 3780749e8deSXin Chen - Sun Microsystems - Beijing China if (af->wait) 3790749e8deSXin Chen - Sun Microsystems - Beijing China rval = aac_return_aif_wait(softs, ctx_p, &fibp); 3800749e8deSXin Chen - Sun Microsystems - Beijing China else 3810749e8deSXin Chen - Sun Microsystems - Beijing China rval = aac_return_aif(softs, ctx_p, &fibp); 3820749e8deSXin Chen - Sun Microsystems - Beijing China } 3830749e8deSXin Chen - Sun Microsystems - Beijing China else 3840749e8deSXin Chen - Sun Microsystems - Beijing China rval = EFAULT; 3850749e8deSXin Chen - Sun Microsystems - Beijing China 3860749e8deSXin Chen - Sun Microsystems - Beijing China finish: 3870749e8deSXin Chen - Sun Microsystems - Beijing China if (rval == 0) { 3880749e8deSXin Chen - Sun Microsystems - Beijing China if (ddi_copyout(fibp, 3890749e8deSXin Chen - Sun Microsystems - Beijing China #ifdef _LP64 3900749e8deSXin Chen - Sun Microsystems - Beijing China (void *)(uint64_t)af->aif_fib, 3910749e8deSXin Chen - Sun Microsystems - Beijing China #else 3920749e8deSXin Chen - Sun Microsystems - Beijing China (void *)af->aif_fib, 3930749e8deSXin Chen - Sun Microsystems - Beijing China #endif 3940749e8deSXin Chen - Sun Microsystems - Beijing China sizeof (struct aac_fib), mode) != 0) 3950749e8deSXin Chen - Sun Microsystems - Beijing China rval = EFAULT; 3960749e8deSXin Chen - Sun Microsystems - Beijing China } 397942c5e3cSpl196000 return (rval); 398942c5e3cSpl196000 } 399942c5e3cSpl196000 400942c5e3cSpl196000 static int 401942c5e3cSpl196000 aac_close_getadapter_fib(struct aac_softstate *softs, intptr_t arg) 402942c5e3cSpl196000 { 4030749e8deSXin Chen - Sun Microsystems - Beijing China struct aac_fib_context *ctx_p; 404942c5e3cSpl196000 405942c5e3cSpl196000 DBCALLED(softs, 2); 406942c5e3cSpl196000 407942c5e3cSpl196000 mutex_enter(&softs->aifq_mutex); 4080749e8deSXin Chen - Sun Microsystems - Beijing China for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) { 4090749e8deSXin Chen - Sun Microsystems - Beijing China if (ctx_p->unique != (uint32_t)arg) 410942c5e3cSpl196000 continue; 411942c5e3cSpl196000 4120749e8deSXin Chen - Sun Microsystems - Beijing China if (ctx_p == softs->fibctx_p) 4130749e8deSXin Chen - Sun Microsystems - Beijing China softs->fibctx_p = ctx_p->next; 414942c5e3cSpl196000 else 4150749e8deSXin Chen - Sun Microsystems - Beijing China ctx_p->prev->next = ctx_p->next; 4160749e8deSXin Chen - Sun Microsystems - Beijing China if (ctx_p->next) 4170749e8deSXin Chen - Sun Microsystems - Beijing China ctx_p->next->prev = ctx_p->prev; 418942c5e3cSpl196000 break; 419942c5e3cSpl196000 } 420942c5e3cSpl196000 mutex_exit(&softs->aifq_mutex); 4210749e8deSXin Chen - Sun Microsystems - Beijing China if (ctx_p) 4220749e8deSXin Chen - Sun Microsystems - Beijing China kmem_free(ctx_p, sizeof (struct aac_fib_context)); 423942c5e3cSpl196000 424942c5e3cSpl196000 return (0); 425942c5e3cSpl196000 } 426942c5e3cSpl196000 427942c5e3cSpl196000 /* 428942c5e3cSpl196000 * The following function comes from Adaptec: 429942c5e3cSpl196000 * 430942c5e3cSpl196000 * SRB is required for the new management tools 431942c5e3cSpl196000 * Note: SRB passed down from IOCTL is always in CPU endianness. 432942c5e3cSpl196000 */ 433942c5e3cSpl196000 static int 434942c5e3cSpl196000 aac_send_raw_srb(struct aac_softstate *softs, dev_t dev, intptr_t arg, int mode) 435942c5e3cSpl196000 { 436942c5e3cSpl196000 struct aac_cmd *acp; 437942c5e3cSpl196000 struct aac_fib *fibp; 438942c5e3cSpl196000 struct aac_srb *srb; 439942c5e3cSpl196000 uint32_t usr_fib_size; 440942c5e3cSpl196000 uint32_t srb_sgcount; 441942c5e3cSpl196000 struct aac_umem_sge *usgt = NULL; 442942c5e3cSpl196000 struct aac_umem_sge *usge; 443942c5e3cSpl196000 ddi_umem_cookie_t cookie; 444942c5e3cSpl196000 int umem_flags = 0; 445942c5e3cSpl196000 int direct = 0; 446942c5e3cSpl196000 int locked = 0; 447942c5e3cSpl196000 caddr_t addrlo = (caddr_t)-1; 448942c5e3cSpl196000 caddr_t addrhi = 0; 449942c5e3cSpl196000 struct aac_sge *sge, *sge0; 450942c5e3cSpl196000 int sg64; 451942c5e3cSpl196000 int rval; 452942c5e3cSpl196000 453942c5e3cSpl196000 DBCALLED(softs, 2); 454942c5e3cSpl196000 455942c5e3cSpl196000 /* Read srb size */ 456942c5e3cSpl196000 if (ddi_copyin(&((struct aac_srb *)arg)->count, &usr_fib_size, 457942c5e3cSpl196000 sizeof (uint32_t), mode) != 0) 458942c5e3cSpl196000 return (EFAULT); 459942c5e3cSpl196000 if (usr_fib_size > (softs->aac_max_fib_size - \ 460942c5e3cSpl196000 sizeof (struct aac_fib_header))) 461942c5e3cSpl196000 return (EINVAL); 462942c5e3cSpl196000 463942c5e3cSpl196000 if ((acp = kmem_zalloc(sizeof (struct aac_cmd) + usr_fib_size + \ 464942c5e3cSpl196000 sizeof (struct aac_fib_header), KM_NOSLEEP)) == NULL) 465942c5e3cSpl196000 return (ENOMEM); 466942c5e3cSpl196000 467942c5e3cSpl196000 acp->fibp = (struct aac_fib *)(acp + 1); 468942c5e3cSpl196000 fibp = acp->fibp; 469942c5e3cSpl196000 srb = (struct aac_srb *)fibp->data; 470942c5e3cSpl196000 471942c5e3cSpl196000 /* Copy in srb */ 472942c5e3cSpl196000 if (ddi_copyin((void *)arg, srb, usr_fib_size, mode) != 0) { 473942c5e3cSpl196000 rval = EFAULT; 474942c5e3cSpl196000 goto finish; 475942c5e3cSpl196000 } 476942c5e3cSpl196000 477942c5e3cSpl196000 srb_sgcount = srb->sg.SgCount; /* No endianness conversion needed */ 478942c5e3cSpl196000 if (srb_sgcount == 0) 479942c5e3cSpl196000 goto send_fib; 480942c5e3cSpl196000 481942c5e3cSpl196000 /* Check FIB size */ 482942c5e3cSpl196000 if (usr_fib_size == (sizeof (struct aac_srb) + \ 483942c5e3cSpl196000 srb_sgcount * sizeof (struct aac_sg_entry64) - \ 484942c5e3cSpl196000 sizeof (struct aac_sg_entry))) { 485942c5e3cSpl196000 sg64 = 1; 486942c5e3cSpl196000 } else if (usr_fib_size == (sizeof (struct aac_srb) + \ 487942c5e3cSpl196000 (srb_sgcount - 1) * sizeof (struct aac_sg_entry))) { 488942c5e3cSpl196000 sg64 = 0; 489942c5e3cSpl196000 } else { 490942c5e3cSpl196000 rval = EINVAL; 491942c5e3cSpl196000 goto finish; 492942c5e3cSpl196000 } 493942c5e3cSpl196000 494942c5e3cSpl196000 /* Read user SG table */ 495942c5e3cSpl196000 if ((usgt = kmem_zalloc(sizeof (struct aac_umem_sge) * srb_sgcount, 496942c5e3cSpl196000 KM_NOSLEEP)) == NULL) { 497942c5e3cSpl196000 rval = ENOMEM; 498942c5e3cSpl196000 goto finish; 499942c5e3cSpl196000 } 500942c5e3cSpl196000 for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) { 501942c5e3cSpl196000 if (sg64) { 50251ccf66eSjd218194 struct aac_sg_entry64 *sg64p = 50351ccf66eSjd218194 (struct aac_sg_entry64 *)srb->sg.SgEntry; 5046d1d45eeSjd218194 50551ccf66eSjd218194 usge->bcount = sg64p->SgByteCount; 5066d1d45eeSjd218194 usge->addr = (caddr_t) 5076d1d45eeSjd218194 #ifndef _LP64 5086d1d45eeSjd218194 (uint32_t) 5096d1d45eeSjd218194 #endif 51051ccf66eSjd218194 sg64p->SgAddress; 511942c5e3cSpl196000 } else { 51251ccf66eSjd218194 struct aac_sg_entry *sgp = srb->sg.SgEntry; 51351ccf66eSjd218194 51451ccf66eSjd218194 usge->bcount = sgp->SgByteCount; 515942c5e3cSpl196000 usge->addr = (caddr_t) 516942c5e3cSpl196000 #ifdef _LP64 517942c5e3cSpl196000 (uint64_t) 518942c5e3cSpl196000 #endif 51951ccf66eSjd218194 sgp->SgAddress; 520942c5e3cSpl196000 } 521942c5e3cSpl196000 acp->bcount += usge->bcount; 522942c5e3cSpl196000 if (usge->addr < addrlo) 523942c5e3cSpl196000 addrlo = usge->addr; 524942c5e3cSpl196000 if ((usge->addr + usge->bcount) > addrhi) 525942c5e3cSpl196000 addrhi = usge->addr + usge->bcount; 526942c5e3cSpl196000 } 527942c5e3cSpl196000 if (acp->bcount > softs->buf_dma_attr.dma_attr_maxxfer) { 528942c5e3cSpl196000 AACDB_PRINT(softs, CE_NOTE, 529942c5e3cSpl196000 "large srb xfer size received %d\n", acp->bcount); 530942c5e3cSpl196000 rval = EINVAL; 531942c5e3cSpl196000 goto finish; 532942c5e3cSpl196000 } 533942c5e3cSpl196000 534942c5e3cSpl196000 /* Lock user buffers */ 535942c5e3cSpl196000 if (srb->flags & SRB_DataIn) { 536942c5e3cSpl196000 umem_flags |= DDI_UMEMLOCK_READ; 537942c5e3cSpl196000 direct |= B_READ; 538942c5e3cSpl196000 } 539942c5e3cSpl196000 if (srb->flags & SRB_DataOut) { 540942c5e3cSpl196000 umem_flags |= DDI_UMEMLOCK_WRITE; 541942c5e3cSpl196000 direct |= B_WRITE; 542942c5e3cSpl196000 } 543942c5e3cSpl196000 addrlo = (caddr_t)((uintptr_t)addrlo & (uintptr_t)PAGEMASK); 544942c5e3cSpl196000 rval = ddi_umem_lock(addrlo, (((size_t)addrhi + PAGEOFFSET) & \ 545942c5e3cSpl196000 PAGEMASK) - (size_t)addrlo, umem_flags, &cookie); 546942c5e3cSpl196000 if (rval != 0) { 547942c5e3cSpl196000 AACDB_PRINT(softs, CE_NOTE, "ddi_umem_lock failed: %d", 548942c5e3cSpl196000 rval); 549942c5e3cSpl196000 goto finish; 550942c5e3cSpl196000 } 551942c5e3cSpl196000 locked = 1; 552942c5e3cSpl196000 553942c5e3cSpl196000 /* Allocate DMA for user buffers */ 554942c5e3cSpl196000 for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) { 555942c5e3cSpl196000 struct buf *bp; 556942c5e3cSpl196000 557a74f7440Spl196000 bp = ddi_umem_iosetup(cookie, (uintptr_t)usge->addr - \ 558a74f7440Spl196000 (uintptr_t)addrlo, usge->bcount, direct, dev, 0, NULL, 55958bc78c7SXin Chen DDI_UMEM_NOSLEEP); 560942c5e3cSpl196000 if (bp == NULL) { 561942c5e3cSpl196000 AACDB_PRINT(softs, CE_NOTE, "ddi_umem_iosetup failed"); 56258bc78c7SXin Chen rval = ENOMEM; 563942c5e3cSpl196000 goto finish; 564942c5e3cSpl196000 } 565942c5e3cSpl196000 if (aac_cmd_dma_alloc(softs, &usge->acp, bp, 0, NULL_FUNC, 566942c5e3cSpl196000 0) != AACOK) { 567942c5e3cSpl196000 rval = EFAULT; 568942c5e3cSpl196000 goto finish; 569942c5e3cSpl196000 } 570942c5e3cSpl196000 acp->left_cookien += usge->acp.left_cookien; 571942c5e3cSpl196000 if (acp->left_cookien > softs->aac_sg_tablesize) { 572942c5e3cSpl196000 AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d", 573942c5e3cSpl196000 acp->left_cookien); 574942c5e3cSpl196000 rval = EINVAL; 575942c5e3cSpl196000 goto finish; 576942c5e3cSpl196000 } 577942c5e3cSpl196000 } 578942c5e3cSpl196000 579942c5e3cSpl196000 /* Construct aac cmd SG table */ 580942c5e3cSpl196000 if ((sge = kmem_zalloc(sizeof (struct aac_sge) * acp->left_cookien, 581942c5e3cSpl196000 KM_NOSLEEP)) == NULL) { 582942c5e3cSpl196000 rval = ENOMEM; 583942c5e3cSpl196000 goto finish; 584942c5e3cSpl196000 } 585942c5e3cSpl196000 acp->sgt = sge; 586942c5e3cSpl196000 for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) { 587942c5e3cSpl196000 for (sge0 = usge->acp.sgt; 588942c5e3cSpl196000 sge0 < &usge->acp.sgt[usge->acp.left_cookien]; 589942c5e3cSpl196000 sge0++, sge++) 590942c5e3cSpl196000 *sge = *sge0; 591942c5e3cSpl196000 } 592942c5e3cSpl196000 593942c5e3cSpl196000 send_fib: 594942c5e3cSpl196000 acp->cmdlen = srb->cdb_size; 595942c5e3cSpl196000 acp->timeout = srb->timeout; 596942c5e3cSpl196000 597942c5e3cSpl196000 /* Send FIB command */ 598942c5e3cSpl196000 acp->aac_cmd_fib = softs->aac_cmd_fib_scsi; 59958bc78c7SXin Chen #ifdef DEBUG 60058bc78c7SXin Chen acp->fib_flags = AACDB_FLAGS_FIB_SRB; 60158bc78c7SXin Chen #endif 602942c5e3cSpl196000 if ((rval = aac_send_fib(softs, acp)) != 0) 603942c5e3cSpl196000 goto finish; 604942c5e3cSpl196000 605942c5e3cSpl196000 /* Status struct */ 606942c5e3cSpl196000 if (ddi_copyout((struct aac_srb_reply *)fibp->data, 607942c5e3cSpl196000 ((uint8_t *)arg + usr_fib_size), 608942c5e3cSpl196000 sizeof (struct aac_srb_reply), mode) != 0) { 609942c5e3cSpl196000 rval = EFAULT; 610942c5e3cSpl196000 goto finish; 611942c5e3cSpl196000 } 612942c5e3cSpl196000 613942c5e3cSpl196000 rval = 0; 614942c5e3cSpl196000 finish: 615942c5e3cSpl196000 if (acp->sgt) 616942c5e3cSpl196000 kmem_free(acp->sgt, sizeof (struct aac_sge) * \ 617942c5e3cSpl196000 acp->left_cookien); 618942c5e3cSpl196000 if (usgt) { 619942c5e3cSpl196000 for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) { 620942c5e3cSpl196000 if (usge->acp.sgt) 621942c5e3cSpl196000 kmem_free(usge->acp.sgt, 622942c5e3cSpl196000 sizeof (struct aac_sge) * \ 623942c5e3cSpl196000 usge->acp.left_cookien); 624942c5e3cSpl196000 aac_free_dmamap(&usge->acp); 625942c5e3cSpl196000 if (usge->acp.bp) 626942c5e3cSpl196000 freerbuf(usge->acp.bp); 627942c5e3cSpl196000 } 628942c5e3cSpl196000 kmem_free(usgt, sizeof (struct aac_umem_sge) * srb_sgcount); 629942c5e3cSpl196000 } 630942c5e3cSpl196000 if (locked) 631942c5e3cSpl196000 ddi_umem_unlock(cookie); 632942c5e3cSpl196000 kmem_free(acp, sizeof (struct aac_cmd) + usr_fib_size + \ 633942c5e3cSpl196000 sizeof (struct aac_fib_header)); 634942c5e3cSpl196000 return (rval); 635942c5e3cSpl196000 } 636942c5e3cSpl196000 637942c5e3cSpl196000 /*ARGSUSED*/ 638942c5e3cSpl196000 static int 639942c5e3cSpl196000 aac_get_pci_info(struct aac_softstate *softs, intptr_t arg, int mode) 640942c5e3cSpl196000 { 641942c5e3cSpl196000 union aac_pci_info_align un; 642942c5e3cSpl196000 struct aac_pci_info *resp = &un.d; 643f42c2f53Szhongyan gu - Sun Microsystems - Beijing China pci_regspec_t *pci_rp; 644f42c2f53Szhongyan gu - Sun Microsystems - Beijing China uint_t num; 645942c5e3cSpl196000 646942c5e3cSpl196000 DBCALLED(softs, 2); 647942c5e3cSpl196000 648f42c2f53Szhongyan gu - Sun Microsystems - Beijing China if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, softs->devinfo_p, 649f42c2f53Szhongyan gu - Sun Microsystems - Beijing China DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &num) != 650f42c2f53Szhongyan gu - Sun Microsystems - Beijing China DDI_PROP_SUCCESS) 651f42c2f53Szhongyan gu - Sun Microsystems - Beijing China return (EINVAL); 652f42c2f53Szhongyan gu - Sun Microsystems - Beijing China if (num < (sizeof (pci_regspec_t) / sizeof (int))) { 653f42c2f53Szhongyan gu - Sun Microsystems - Beijing China ddi_prop_free(pci_rp); 654f42c2f53Szhongyan gu - Sun Microsystems - Beijing China return (EINVAL); 655f42c2f53Szhongyan gu - Sun Microsystems - Beijing China } 656f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 657f42c2f53Szhongyan gu - Sun Microsystems - Beijing China resp->bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); 658f42c2f53Szhongyan gu - Sun Microsystems - Beijing China resp->slot = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 659f42c2f53Szhongyan gu - Sun Microsystems - Beijing China ddi_prop_free(pci_rp); 660942c5e3cSpl196000 661942c5e3cSpl196000 if (ddi_copyout(resp, (void *)arg, 662942c5e3cSpl196000 sizeof (struct aac_pci_info), mode) != 0) 663942c5e3cSpl196000 return (EFAULT); 664942c5e3cSpl196000 return (0); 665942c5e3cSpl196000 } 666942c5e3cSpl196000 667942c5e3cSpl196000 static int 668942c5e3cSpl196000 aac_query_disk(struct aac_softstate *softs, intptr_t arg, int mode) 669942c5e3cSpl196000 { 670942c5e3cSpl196000 union aac_query_disk_align un; 671942c5e3cSpl196000 struct aac_query_disk *qdisk = &un.d; 672942c5e3cSpl196000 struct aac_container *dvp; 673942c5e3cSpl196000 674942c5e3cSpl196000 DBCALLED(softs, 2); 675942c5e3cSpl196000 676942c5e3cSpl196000 if (ddi_copyin((void *)arg, qdisk, sizeof (*qdisk), mode) != 0) 677942c5e3cSpl196000 return (EFAULT); 678942c5e3cSpl196000 679942c5e3cSpl196000 if (qdisk->container_no == -1) { 680942c5e3cSpl196000 qdisk->container_no = qdisk->target * 16 + qdisk->lun; 681942c5e3cSpl196000 } else if (qdisk->bus == -1 && qdisk->target == -1 && 682942c5e3cSpl196000 qdisk->lun == -1) { 683942c5e3cSpl196000 if (qdisk->container_no >= AAC_MAX_CONTAINERS) 684942c5e3cSpl196000 return (EINVAL); 685942c5e3cSpl196000 qdisk->bus = 0; 686942c5e3cSpl196000 qdisk->target = (qdisk->container_no & 0xf); 687942c5e3cSpl196000 qdisk->lun = (qdisk->container_no >> 4); 688942c5e3cSpl196000 } else { 689942c5e3cSpl196000 return (EINVAL); 690942c5e3cSpl196000 } 691942c5e3cSpl196000 692942c5e3cSpl196000 mutex_enter(&softs->io_lock); 693942c5e3cSpl196000 dvp = &softs->containers[qdisk->container_no]; 69458bc78c7SXin Chen qdisk->valid = AAC_DEV_IS_VALID(&dvp->dev); 695942c5e3cSpl196000 qdisk->locked = dvp->locked; 696942c5e3cSpl196000 qdisk->deleted = dvp->deleted; 697942c5e3cSpl196000 mutex_exit(&softs->io_lock); 698942c5e3cSpl196000 699942c5e3cSpl196000 if (ddi_copyout(qdisk, (void *)arg, sizeof (*qdisk), mode) != 0) 700942c5e3cSpl196000 return (EFAULT); 701942c5e3cSpl196000 return (0); 702942c5e3cSpl196000 } 703942c5e3cSpl196000 704942c5e3cSpl196000 static int 705942c5e3cSpl196000 aac_delete_disk(struct aac_softstate *softs, intptr_t arg, int mode) 706942c5e3cSpl196000 { 707942c5e3cSpl196000 union aac_delete_disk_align un; 708942c5e3cSpl196000 struct aac_delete_disk *ddisk = &un.d; 709942c5e3cSpl196000 struct aac_container *dvp; 710942c5e3cSpl196000 int rval = 0; 711942c5e3cSpl196000 712942c5e3cSpl196000 DBCALLED(softs, 2); 713942c5e3cSpl196000 714942c5e3cSpl196000 if (ddi_copyin((void *)arg, ddisk, sizeof (*ddisk), mode) != 0) 715942c5e3cSpl196000 return (EFAULT); 716942c5e3cSpl196000 717942c5e3cSpl196000 if (ddisk->container_no >= AAC_MAX_CONTAINERS) 718942c5e3cSpl196000 return (EINVAL); 719942c5e3cSpl196000 720942c5e3cSpl196000 mutex_enter(&softs->io_lock); 721942c5e3cSpl196000 dvp = &softs->containers[ddisk->container_no]; 722942c5e3cSpl196000 /* 723942c5e3cSpl196000 * We don't trust the userland to tell us when to delete 724942c5e3cSpl196000 * a container, rather we rely on an AIF coming from the 725942c5e3cSpl196000 * controller. 726942c5e3cSpl196000 */ 72758bc78c7SXin Chen if (AAC_DEV_IS_VALID(&dvp->dev)) { 728942c5e3cSpl196000 if (dvp->locked) 729942c5e3cSpl196000 rval = EBUSY; 730942c5e3cSpl196000 } 731942c5e3cSpl196000 mutex_exit(&softs->io_lock); 732942c5e3cSpl196000 733942c5e3cSpl196000 return (rval); 734942c5e3cSpl196000 } 735942c5e3cSpl196000 736942c5e3cSpl196000 /* 737942c5e3cSpl196000 * The following function comes from Adaptec to support creation of arrays 738942c5e3cSpl196000 * bigger than 2TB. 739942c5e3cSpl196000 */ 740942c5e3cSpl196000 static int 741942c5e3cSpl196000 aac_supported_features(struct aac_softstate *softs, intptr_t arg, int mode) 742942c5e3cSpl196000 { 743942c5e3cSpl196000 union aac_features_align un; 744942c5e3cSpl196000 struct aac_features *f = &un.d; 745942c5e3cSpl196000 746942c5e3cSpl196000 DBCALLED(softs, 2); 747942c5e3cSpl196000 748942c5e3cSpl196000 if (ddi_copyin((void *)arg, f, sizeof (*f), mode) != 0) 749942c5e3cSpl196000 return (EFAULT); 750942c5e3cSpl196000 751942c5e3cSpl196000 /* 752942c5e3cSpl196000 * When the management driver receives FSACTL_GET_FEATURES ioctl with 753942c5e3cSpl196000 * ALL zero in the featuresState, the driver will return the current 754942c5e3cSpl196000 * state of all the supported features, the data field will not be 755942c5e3cSpl196000 * valid. 756942c5e3cSpl196000 * When the management driver receives FSACTL_GET_FEATURES ioctl with 757942c5e3cSpl196000 * a specific bit set in the featuresState, the driver will return the 758942c5e3cSpl196000 * current state of this specific feature and whatever data that are 759942c5e3cSpl196000 * associated with the feature in the data field or perform whatever 760942c5e3cSpl196000 * action needed indicates in the data field. 761942c5e3cSpl196000 */ 762942c5e3cSpl196000 if (f->feat.fValue == 0) { 763942c5e3cSpl196000 f->feat.fBits.largeLBA = 764942c5e3cSpl196000 (softs->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 765*3fced439Szhongyan gu - Sun Microsystems - Beijing China f->feat.fBits.JBODSupport = 766*3fced439Szhongyan gu - Sun Microsystems - Beijing China (softs->flags & AAC_FLAGS_JBOD) ? 1 : 0; 767942c5e3cSpl196000 /* TODO: In the future, add other features state here as well */ 768942c5e3cSpl196000 } else { 769942c5e3cSpl196000 if (f->feat.fBits.largeLBA) 770942c5e3cSpl196000 f->feat.fBits.largeLBA = 771942c5e3cSpl196000 (softs->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 772*3fced439Szhongyan gu - Sun Microsystems - Beijing China if (f->feat.fBits.JBODSupport) 773*3fced439Szhongyan gu - Sun Microsystems - Beijing China f->feat.fBits.JBODSupport = 774*3fced439Szhongyan gu - Sun Microsystems - Beijing China (softs->flags & AAC_FLAGS_JBOD) ? 1 : 0; 775942c5e3cSpl196000 /* TODO: Add other features state and data in the future */ 776942c5e3cSpl196000 } 777942c5e3cSpl196000 778942c5e3cSpl196000 if (ddi_copyout(f, (void *)arg, sizeof (*f), mode) != 0) 779942c5e3cSpl196000 return (EFAULT); 780942c5e3cSpl196000 return (0); 781942c5e3cSpl196000 } 782