sata.c revision f8a673ad9145b262edb65a98fb3fb92027d23a05
* For DDI_ATTACH command: * sata_hba_inst structure is allocated here and initialized with pointers to * SATA framework implementation of required scsi tran functions. * The scsi_tran's tran_hba_private field is used by SATA Framework to point * to the soft structure (sata_hba_inst) allocated by SATA framework for * SATA HBA instance related data. * The scsi_tran's tran_hba_private field is used by SATA framework to * store a pointer to per-HBA-instance of sata_hba_inst structure. * The sata_hba_inst structure is cross-linked to scsi tran structure. * Among other info, a pointer to sata_hba_tran structure is stored in * sata_hba_inst. The sata_hba_inst structures for different HBA instances are * linked together into the list, pointed to by sata_hba_list. * On the first HBA instance attach the sata event thread is initialized. * Attachment points are created for all SATA ports of the HBA being attached. * All HBA instance's SATA ports are probed and type of plugged devices is * determined. For each device of a supported type, a target node is created. * DDI_SUCCESS is returned when attachment process is successful, * DDI_FAILURE is returned otherwise. * For DDI_RESUME command: * Not implemented at this time (postponed until phase 2 of the development). "sata_hba_attach: node %s (%s%d)\n",
* Postponed until phase 2 of the development "sata_hba_attach: invalid sata_hba_tran"));
* Allocate and initialize SCSI tran structure. * SATA copy of tran_bus_config is provided to create port nodes. * Allocate soft structure for SATA HBA instance. * There is a separate softstate for each HBA instance. * scsi_trans's tran_hba_private is used by SATA Framework to point to * soft structure allocated by SATA framework for * SATA HBA instance related data. "failed to create hba sata prop"));
* Save pointers in hba instance soft state. * Create a task queue to handle emulated commands completion * Use node name, dash, instance number as the queue name. * Create events thread if not created yet. * Link this hba instance into the list. * The first instance of HBA is attached. * all SATA devices. It is done here and now, to eliminate the * possibility of the dynamic, programatic modification of the * queue depth via global (and public) sata_max_queue_depth * variable (this would require special handling in HBA drivers) * Create SATA HBA devctl minor node for sata_hba_open, close, ioctl * SATA HBA driver should not use its own open/close entry points. * Make sure that instance number doesn't overflow * when forming minor numbers. "cannot create devctl minor node");
* Set-up kstats here, if necessary. * (postponed until future phase of the development). * Indicate that HBA is attached. This will enable events processing * Probe controller ports. This operation will describe a current * We may end-up with just a controller with no devices attached. * For the ports with a supported device attached, device target nodes * are created and devices are initialized. * Called by SATA HBA from to detach an instance of the driver. * For DDI_DETACH command: * Free local structures allocated for SATA HBA instance during * sata_hba_attach processing. * Returns DDI_SUCCESS when HBA was detached, DDI_FAILURE otherwise. * For DDI_SUSPEND command: * Not implemented at this time (postponed until phase 2 of the development) * When the last HBA instance is detached, the event daemon is terminated. * NOTE: cport support only, no port multiplier support. * Free all target nodes - at this point * devices should be at least offlined * otherwise scsi_hba_detach() should not be called. * Disable sata event daemon processing for this HBA * Remove event daemon thread, if it is last HBA instance. /* Remove this HBA instance from the HBA list */ * At this point there should be no target nodes attached. * Detach and destroy device and port info structures. /* Release device structure */ * Postponed until phase 2 * Called by an HBA drive from _fini() routine. * Unregisters SATA HBA instance/SATA framework pair from the scsi framework. "sata_hba_fini: name %s\n",
* Default open and close routine for sata_hba framework. * 0 if node was open successfully, error code otherwise. * 0 if node was closed successfully, error code otherwise. * Standard IOCTL commands for SATA hotplugging. * Implemented DEVCTL_AP commands: * Commands passed to default ndi ioctl handler: * All other cmds are passed to HBA if it provide ioctl handler, or failed * error code if operation failed. * NOTE: Port Multiplier is not supported. * There may be more cases that we want to pass to default * handler rather than fail them. /* read devctl ioctl data */ /* Only cport is considered now, i.e. SATA_ADDR_CPORT */ * Cannot process ioctl request now. Come back later. /* Block event processing for this port */ * Normally, cfgadm sata plugin will try to offline * (unconfigure) device before this request. Nevertheless, * if a device is still configured, we need to * attempt to offline and unconfigure device first, and we will * deactivate the port regardless of the unconfigure * The unconfigure operation uses generic nexus operation to * offline a device. It leaves a target device node attached. * and obviously sata_drive_info attached as well, because * from the hardware point of view nothing has changed. * The sata cfgadm pluging will invoke this operation only if * port was found in the disconnect state (failed state * is also treated as the disconnected state). * If port activation is successful and a device is found * attached to the port, the initialization sequence is * executed to probe the port and attach * a device structure to a port structure. The device is not * set in configured state (system-wise) by this operation. * A port may be in an active or shutdown state. * If port is in a failed state, operation is aborted. * If a port is in a shutdown state, sata_tran_port_activate() * is invoked prior to any other operation. * Onlining the device involves creating a new target node. * If there is an old target node present (belonging to * previously removed device), the operation is aborted - the * old node has to be released and removed before configure * operation is attempted. /* Copy the return AP-state information to the user space */ * Generic devctl for hardware specific functionality /* Copy in user ioctl data first */ #
endif /* _MULTI_DATAMODEL */ "sata_hba_ioctl: DEVCTL_AP_CONTROL " * To avoid BE/LE and 32/64 issues, a get_size always returns /* Override address qualifier - handle cport only for now */ /* Is the port locked by event processing daemon ? */ * Cannot process ioctl request now. Come back later /* Block event processing for this port */ * There is no protection for configured device. * There is no protection for configured device. * There is no protection for configured devices. * We return here, because common return is for * a single port operation - we have already unlocked * all ports and no dc handle was allocated. * Arbitrarily unconfigure attached device, if any. * Even if the unconfigure fails, proceed with the }
/* End of DEVCTL_AP_CONTROL cmd switch */ * If we got here, we got an IOCTL that SATA HBA Framework * does not recognize. Pass ioctl to HBA driver, in case "IOCTL 0x%2x not supported in SATA framework, " "passthrough to HBA",
cmd);
"IOCTL 0x%2x failed in HBA",
cmd);
}
/* End of main IOCTL switch */ * Create error retrieval sata packet * A sata packet is allocated and set-up to contain specified error retrieval * command and appropriate dma-able data buffer. * No association with any scsi packet is made and no callback routine is * Returns a pointer to sata packet upon successfull packet creation. * Returns NULL, if packet cannot be created. "sata: error recovery request for non-attached device at " /* address is needed now */ * Free error retrieval sata packet * Free sata packet and any associated resources allocated previously by * sata_get_error_retrieval_pkt(). * sata_name_child is for composing the name of the node * the format of the name is "target,0". /* ****************** SCSA required entry points *********************** */ * Implementation of scsi tran_tgt_init. * sata_scsi_tgt_init() initializes scsi_device structure * If successful, DDI_SUCCESS is returned. * DDI_FAILURE is returned if addressed device does not exist * Fail tran_tgt_init for .conf stub node /* Validate scsi device address */ /* sata_device now contains a valid sata address */ * Check if we need to create a legacy devid (i.e cmdk style) for * HBA devinfo node will have the property "use-cmdk-devid-format" * if we need to create cmdk-style devid for all the disk devices * attached to this controller. This property may have been set * from HBA driver's .conf file or by the HBA driver in its "use-cmdk-devid-format", 0) ==
1)) {
/* register a legacy devid for this target node */ * 'Identify Device Data' does not always fit in standard SCSI * INQUIRY data, so establish INQUIRY_* properties with full-form #
else /* _LITTLE_ENDIAN */#
endif /* _LITTLE_ENDIAN */ /* split model into into vid/pid */ if ((*
pid ==
' ') || (*
pid ==
'\t'))
*
pid++ = 0;
/* terminate vid, establish pid */ vid =
NULL;
/* vid will stay "ATA " */ * Implementation of scsi tran_tgt_probe. * Probe target, by calling default scsi routine scsi_hba_probe() * Set property "pm-capable" on the target device node, so that * the target driver will not try to fetch scsi cycle counters * before enabling device power-management. "SATA device at port %d: " "will not be power-managed ",
"failure updating pm-capable property"));
* Implementation of scsi tran_tgt_free. * Release all resources allocated for scsi_device /* Validate scsi device address */ /* sata_device now should contain a valid sata address */ * We did not allocate any resources in sata_scsi_tgt_init() * other than few properties. * If devid was previously created but not freed up from * sd(7D) driver (i.e during detach(9F)) then do it here. "use-cmdk-devid-format", 0) ==
1) &&
* Implementation of scsi tran_init_pkt * Upon successful return, scsi pkt buffer has DMA resources allocated. * It seems that we should always allocate pkt, even if the address is * for non-existing device - just use some default for dma_attr. * The reason is that there is no way to communicate this to a caller here. * Subsequent call to sata_scsi_start may fail appropriately. * Simply returning NULL does not seem to discourage a target driver... * Returns a pointer to initialized scsi_pkt, or NULL otherwise. * We need to translate the address, even if it could be * a bogus one, for a non-existing device * Have to allocate a brand new scsi packet. * We need to operate with auto request sense enabled. /* Fill scsi packet structure */ * pkt_hba_private will point to sata pkt txlate structure /* Could not allocate sata pkt */ /* Pkt is available already: spx->txlt_scsi_pkt == pkt; */ * We use an adjusted version of the dma_attr, to account * for device addressing limitations. * sata_adjust_dma_attr() will handle sdinfo == NULL which may * happen when a device is not yet configured. /* NULL sdinfo may be passsed to sata_adjust_dma_attr() */ * Allocate necessary DMA resources for the packet's data buffer * In case of read/write commands, DMA resource allocation here is * based on the premise that the transfer length specified in * the read/write scsi cdb will match exactly DMA resources - * returning correct packet residue is crucial. * If a DMA allocation request fails with * DDI_DMA_NOMAPPING, indicate the error by calling * bioerror(9F) with bp and an error code of EFAULT. * If a DMA allocation request fails with * DDI_DMA_TOOBIG, indicate the error by calling * bioerror(9F) with bp and an error code of EINVAL. * For DDI_DMA_NORESOURCES, we may have some of them allocated. * Request may be repeated later - there is no real error. * Since this is a new packet, we can clean-up * This is a re-used packet. It will be target driver's * responsibility to eventually destroy it (which * will free allocated resources). * Here, we just "complete" the request, leaving * allocated resources intact, so the request may /* Set number of bytes that are not yet accounted for */ * Implementation of scsi tran_start. * Translate scsi cmd into sata operation and return status. * ATAPI CDBs are passed to ATAPI devices - the device determines what commands * For SATA hard disks, supported scsi commands: * SCMD_MODE_SENSE (specific pages) * SCMD_MODE_SENSE_G1 (specific pages) * SCMD_MODE_SELECT (specific pages) * SCMD_MODE_SELECT_G1 (specific pages) * SCMD_SYNCHRONIZE_CACHE_G1 * All other commands are rejected as unsupported. * TRAN_ACCEPT if command was executed successfully or accepted by HBA driver * for execution. TRAN_ACCEPT may be returned also if device was removed but * a callback could be scheduled. * TRAN_BADPKT if cmd was directed to invalid address. * TRAN_FATAL_ERROR is command was rejected due to hardware error, including * some unspecified error. TRAN_FATAL_ERROR may be also returned if a device * was removed and there was no callback specified in scsi pkt. * TRAN_BUSY if command could not be executed becasue HBA driver or SATA * framework was busy performing some other operation(s). * The sd target driver is checking CMD_DEV_GONE pkt_reason * only in callback function (for normal requests) and * So, if the callback is available, we need to do * the callback rather than returning TRAN_FATAL_ERROR here. /* scsi callback required */ /* Scheduling the callback failed */ /* No callback available */ "sata_scsi_start atapi: rval %d\n",
rval);
/* ATA Disk commands processing starts here */ /* Mapped to identify device */ * SAT "SATA to ATA Translation" doc specifies translation * to ATA CHECK POWER MODE. /* Mapping depends on the command */ * Always No Sense, since we force ARQ /* Other cases will be filed later */ /* postponed until phase 2 of the development */ "sata_scsi_start: rval %d\n",
rval);
* Implementation of scsi tran_abort. * Abort specific pkt or all packets. * Returns 1 if one or more packets were aborted, returns 0 otherwise * May be called from an interrupt level. "sata_scsi_abort: %s at target: 0x%x\n",
* Although we do not have specific packet, we still need * dummy packet structure to pass device address to HBA. * Allocate one, without sleeping. Fail if pkt cannot be "could not allocate sata_pkt"));
return (0);
/* Bad scsi pkt */ /* extract pointer to sata pkt */ /* Send abort request to HBA */ /* Else, something did not go right */ * Implementation of scsi tran_reset. * RESET_ALL request is translated into port reset. * RESET_TARGET requests is translated into a device reset, * RESET_LUN request is accepted only for LUN 0 and translated into * The target reset should cause all HBA active and queued packets to * be terminated and returned with pkt reason SATA_PKT_RESET prior to * the return. HBA should report reset event for the device. * Returns 1 upon success, 0 upon failure. "sata_scsi_reset: level %d target: 0x%x\n",
/* port reset - cport only */ /* reset device (device attached) */ * Supported capabilities for SATA hard disks: * auto-rqsense (always supported) * tagged-qing (supported if HBA supports it) * untagged-qing (could be supported if disk supports it, but because * caching behavior allowing untagged queuing actually * results in reduced performance. sd tries to throttle * back to only 3 outstanding commands, which may * work for real SCSI disks, but with read ahead * caching, having more than 1 outstanding command * results in cache thrashing.) * interconnect-type (INTERCONNECT_SATA) * Supported capabilities for ATAPI CD/DVD devices: * auto-rqsense (always supported) * interconnect-type (INTERCONNECT_SATA) * Supported capabilities for ATAPI TAPE devices: * auto-rqsense (always supported) * Supported capabilities for SATA ATAPI hard disks: * auto-rqsense (always supported) * interconnect-type (INTERCONNECT_SATA) * Request for other capabilities is rejected as unsupported. * Returns supported capability value, or -1 if capability is unsuppported or * the address is invalid - no device. "sata_scsi_getcap: target: 0x%x, cap: %s\n",
* We want to process the capabilities on per port granularity. * So, we are specifically restricting ourselves to whom != 0 * to exclude the controller wide handling. rval =
1;
/* ARQ supported, turned on */ * untagged queuing cause a performance inversion because of * the way sd operates. Because of this reason we do not rval =
1;
/* Untagged queuing available */ rval = -
1;
/* Untagged queuing not available */ rval =
1;
/* Tagged queuing available */ rval = -
1;
/* Tagged queuing not available */ /* We rely on the fact that dma_attr_maxxfer < 0x80000000 */ * Implementation of scsi tran_setcap * Only SCSI_CAP_UNTAGGED_QING and SCSI_CAP_TAGGED_QING are changeable. * We want to process the capabilities on per port granularity. * So, we are specifically restricting ourselves to whom != 0 * to exclude the controller wide handling. /* This can TCQ or NCQ */ * Implementations of scsi tran_destroy_pkt. * Free resources allocated by sata_scsi_init_pkt() * Implementation of scsi tran_dmafree. * Free DMA resources allocated by sata_scsi_init_pkt() * Implementation of scsi tran_sync_pkt. * The assumption below is that pkt is unique - there is no need to check ap * Synchronize DMA buffer and, if the intermediate buffer is used, copy data /* Intermediate DMA buffer used */ /* Sync the buffer for device or for CPU */ /* Intermediate DMA buffer used for read */ /* ******************* SATA - SCSI Translation functions **************** */ * SCSI to SATA pkt and command translation and SATA to SCSI status/error * Checks if a device exists and can be access and translates common * scsi_pkt data to sata_pkt data. * Returns TRAN_ACCEPT and scsi pkt_reason CMD_CMPLT if device exists and * Returns TRAN_ACCEPT and scsi pkt_reason CMD_DEV_GONE if device does not * exist and pkt_comp callback was scheduled. * Returns other TRAN_XXXXX values when error occured and command should be * rejected with the returned TRAN_XXXXX value. * This function should be called with port mutex held. /* all other values to 0/FALSE */ * Pkt_reason has to be set if the pkt_comp callback is invoked, * and that implies TRAN_ACCEPT return value. Any other returned value * indicates that the scsi packet was not accepted (the reason will not * be checked by the scsi target driver). * To make debugging easier, we set pkt_reason to know value here. * It may be changed later when different completion reason is /* Invalid address or invalid device type */ /* valid address but no device - it has disappeared ? */ * The sd target driver is checking CMD_DEV_GONE pkt_reason * only in callback function (for normal requests) and * So, if the callback is available, we need to do * the callback rather than returning TRAN_FATAL_ERROR here. /* scsi callback required */ /* Scheduling the callback failed */ /* all OK; pkt reason will be overwritten later */ * If in an interrupt context, reject packet if it is to be * executed in polling mode "sata_scsi_start: rejecting synchronous command because " "of interrupt context\n",
NULL);
* If device is in reset condition, reject the packet with * 1. system is panicking (dumping) * In such case only one thread is running and there is no way to * 2. cfgadm operation is is progress (internal APCTL lock is set) * Some cfgadm operations involve drive commands, so reset condition * needs to be ignored for IOCTL operations. "sata_scsi_start: rejecting command because " "of device reset state\n",
NULL);
* Fix the dev_type in the sata_pkt->satapkt_device. It was not set by * sata_scsi_pkt_init() because pkt init had to work also with * Now we know that the packet was set-up for a real device, so its * At this point the generic translation routine determined that the * scsi packet should be accepted. Packet completion reason may be * changed later when a different completion reason is determined. /* Synchronous execution */ /* Asynchronous execution */ /* Convert queuing information */ /* Always limit pkt time */ /* Pass on scsi_pkt time */ * Translate ATA Identify Device data to SCSI Inquiry data. * This function may be called only for ATA devices. * This function should not be called for ATAPI devices - they * respond directly to SCSI Inquiry command. * SATA Identify Device data has to be valid in sata_rive_info. * Buffer has to accomodate the inquiry length (36 bytes). * This function should be called with a port mutex held. /* Start with a nice clean slate */ * Rely on the dev_type for setting paripheral qualifier. * Assume that DTYPE_RODIRECT applies to CD/DVD R/W devices. * It could be that DTYPE_OPTICAL could also qualify in the future. * ATAPI Inquiry may provide more data to the target driver. inq->
inq_qual = 0;
/* Device type qualifier (obsolete in SCSI3? */ inq->
inq_sync = 0;
/* Supports synchronous data xfers - NO */ * Queuing support - controller has to * support some sort of command queuing. inq->
inq_sftre = 0;
/* Supports Soft Reset option - NO ??? */ /* Swap text fields to match SCSI format */ #
else /* _LITTLE_ENDIAN */#
endif /* _LITTLE_ENDIAN */ * Scsi response set up for invalid command (command not supported) * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields. /* scsi callback required */ /* Scheduling the callback failed */ * Scsi response setup for * emulated non-data command that requires no action/return data * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields. "Scsi_pkt completion reason %x\n",
/* scsi callback required */ /* Scheduling the callback failed */ * SATA translate command: Inquiry / Identify Device * Use cached Identify Device data for now, rather than issuing actual * Device Identify cmd request. If device is detached and re-attached, * asynchromous event processing should fetch and refresh Identify Device * Two VPD pages are supported now: * Vital Product Data page * Unit Serial Number page * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields. #
define EVPD 1 /* Extended Vital Product Data flag */#
define CMDDT 2 /* Command Support Data - Obsolete */ /* Reject not supported request */ /* Valid Inquiry request */ * Because it is fully emulated command storing data * programatically in the specified buffer, release * preallocated DMA resources before storing data in the buffer, * so no unwanted DMA sync would take place. /* Standard Inquiry Data request */ /* Copy no more than requested */ * peripheral_qualifier = 0; * We are dealing only with HD and will be * dealing with CD/DVD devices soon * Request for suported Vital Product Data * pages - assuming only 2 page codes /* Copy no more than requested */ * Request for Unit Serial Number page. /* remaining page length */ * Copy serial number from Identify Device data * words into the inquiry page and swap bytes * Least significant character of the serial * number shall appear as the last byte, * according to SBC-3 spec. * Count trailing spaces to determine the * necessary shift length. * Shift SN string right, so that the last * non-blank character would appear in last * byte of SN field in the page. * 'j' is the shift length. * Add leading spaces - same number as the * We may want to implement this page, when * identifiers are common for SATA devices /* Request for unsupported VPD page */ "Scsi_pkt completion reason %x\n",
/* scsi callback required */ /* Scheduling the callback failed */ * SATA translate command: Request Sense. * Emulated command (ATA version for SATA hard disks) * Always NO SENSE, because any sense data should be reported by ARQ sense. * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields. * Note: There is a mismatch between already implemented Informational * Exception Mode Select page 0x1C and this function. * When MRIE bit is set in page 0x1C, Request Sense is supposed to return * NO SENSE and set additional sense code to the exception code - this is not * Because it is fully emulated command storing data * programatically in the specified buffer, release * preallocated DMA resources before storing data in the buffer, * so no unwanted DMA sync would take place. /* Copy no more than requested */ "Scsi_pkt completion reason %x\n",
/* scsi callback required */ /* Scheduling the callback failed */ * SATA translate command: Test Unit Ready * At the moment this is an emulated command (ATA version for SATA hard disks). * May be translated into Check Power Mode command in the future * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields. /* At this moment, emulate it rather than execute anything */ /* scsi callback required */ /* Scheduling the callback failed */ * SATA translate command: Start Stop Unit * Translation depends on a command: * Start Unit translated into Idle Immediate * Stop Unit translated into Standby Immediate * Unload Media / NOT SUPPORTED YET * Load Media / NOT SUPPROTED YET * Power condition bits are ignored, so is Immediate bit * Requesting synchronous execution. * Returns TRAN_ACCEPT or code returned by sata_hba_start() and * appropriate values in scsi_pkt fields. /* scsi callback required */ /* Scheduling the callback failed */ /* Need to set-up a callback function */ /* Transfer command to HBA */ /* Pkt not accepted for execution */ * If execution is non-synchronous, * a callback function will handle potential errors, translate * the response and will do a callback to a target driver. * If it was synchronous, check execution status using the same "synchronous execution status %x\n",
* SATA translate command: Read Capacity. * Emulated command for SATA disks. * Capacity is retrieved from cached Idenifty Device data. * Identify Device data shows effective disk capacity, not the native * capacity, which may be limitted by Set Max Address command. * This is ATA version for SATA hard disks. * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields. "sata_txlt_read_capacity: ",
NULL);
* Because it is fully emulated command storing data * programatically in the specified buffer, release * preallocated DMA resources before storing data in the buffer, * so no unwanted DMA sync would take place. /* Last logical block address */ /* Need to swap endians to match scsi format */ /* block size - always 512 bytes, for now */ * If a callback was requested, do it now. /* scsi callback required */ /* Scheduling the callback failed */ * SATA translate command: Mode Sense. * Translated into appropriate SATA command or emulated. * Saved Values Page Control (03) are not supported. * NOTE: only caching mode sense page is currently implemented. * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields. int pc;
/* Page Control code */ "sata_txlt_mode_sense, pc %x page code 0x%02x\n",
* Because it is fully emulated command storing data * programatically in the specified buffer, release * preallocated DMA resources before storing data in the buffer, * so no unwanted DMA sync would take place. /* Build mode parameter header */ /* 4-byte mode parameter header */ buf[
len++] = 0;
/* mode data length */ buf[
len++] = 0;
/* medium type */ buf[
len++] = 0;
/* dev-specific param */ /* 8-byte mode parameter header */ buf[
len++] = 0;
/* mode data length */ buf[
len++] = 0;
/* medium type */ buf[
len++] = 0;
/* dev-specific param */ buf[
len++] =
1;
/* long lba descriptor */ buf[
len++] = 0;
/* Block Descriptor length */ /* Build block descriptor only if not disabled (DBD) */ /* Block descriptor - direct-access device format */ /* build regular block descriptor */ buf[
len++] = 0;
/* density code */ }
else if (
bdlen ==
16) {
/* build long lba block descriptor */ buf[
len++] = 0;
/* density code */ * Page 3 and 4 are obsolete and we are not supporting them. * We should eventually deal with following mode pages: * power condition (0x1a), * exception control page (enables SMART) (0x1c), * enclosure management (ses), * protocol-specific port mode (port control). /* Reject not supported request for saved parameters */ /* DAD_MODE_POWER_COND */ /* acoustic management */ /* fix total mode data length */ /* 4-byte mode parameter header */ buf[0] =
len -
1;
/* mode data length */ /* Check allocation length */ * We do not check for possible parameters truncation * (alc_len < len) assuming that the target driver works * correctly. Just avoiding overrun. * Copy no more than requested and possible, buffer-wise. /* scsi callback required */ /* Scheduling the callback failed */ * SATA translate command: Mode Select. * Translated into appropriate SATA command or emulated. * Saving parameters is not supported. * Changing device capacity is not supported (although theoretically * Assumption is that the target driver is working correctly. * More than one SATA command may be executed to perform operations specified * by mode select pages. The first error terminates further execution. * Operations performed successully are not backed-up in such case. * NOTE: Implemented pages: * - informational exception page * - acoustic management page * Caching setup is remembered so it could be re-stored in case of * an unexpected device reset. * If TRAN_ACCEPT is returned, appropriate values are set in scsi_pkt fields. "sata_txlt_mode_select, pc %x page code 0x%02x\n",
* If in interrupt context, reject this packet because it may result * in issuing a synchronous command to HBA. "sata_txlt_mode_select: rejecting command because " "of interrupt context\n",
NULL);
/* Reject not supported request */ * Check the header to skip the block descriptor(s) - we * do not support setting device capacity. * Existing macros do not recognize long LBA dscriptor, * hence manual calculation. /* 6-bytes CMD, 4 bytes header */ goto done;
/* header only */ /* 10-bytes CMD, 8 bytes header */ goto done;
/* header only */ goto done;
/* header + descriptor(s) only */ pllen -=
len;
/* remaining data length */ * We may be executing SATA command and want to execute it * in SYNCH mode, regardless of scsi_pkt setting. * Save scsi_pkt setting and indicate SYNCH mode * len is now the offset to a first mode select page /* No support for SP (saving) */ * The pagelen value indicates the number of * parameter bytes already processed. * The rval is the return value from * The stat indicates the overall status of * Page processing did not succeed - * all error info is already set-up, pllen = 0;
/* this breaks the loop */ * The pagelen value indicates the number of * parameter bytes already processed. * The rval is the return value from * The stat indicates the overall status of * Page processing did not succeed - * all error info is already set-up, pllen = 0;
/* this breaks the loop */ * The pagelen value indicates the number of * parameter bytes already processed. * The rval is the return value from * The stat indicates the overall status of * Page processing did not succeed - * all error info is already set-up, pllen = 0;
/* this breaks the loop */ * If device parameters were modified, fetch and store the new * Identify Device data. Since port mutex could have been released * for accessing HBA driver, we need to re-check device existence. * Following statement has to be changed if this function is * used for devices other than SATA hard disks. * Since port mutex could have been released when * accessing HBA driver, we need to re-check that the * framework still holds the device info structure. * Device still has info structure in the * sata framework. Copy newly fetched info * Could not fetch new data - invalidate * sata_drive_info. That makes device * This changes the overall mode select completion * reason to a failed one !!!!! /* Restore the scsi pkt flags */ /* scsi callback required */ /* Scheduling the callback failed */ * Translate command: Log Sense int pc;
/* Page Control code */ "sata_txlt_log_sense, pc 0x%x, page code 0x%x\n",
* If in interrupt context, reject this packet because it may result * in issuing a synchronous command to HBA. "sata_log_sense: rejecting command because " "of interrupt context\n",
NULL);
/* Reject not supported request for all but cumulative values */ * Because log sense uses local buffers for data retrieval from * the devices and sets the data programatically in the * original specified buffer, release preallocated DMA * resources before storing data in the original buffer, * so no unwanted DMA sync would take place. /* Build log parameter header */ buf[
len++] = 0;
/* reserved */ buf[
len++] = 0;
/* Zero out page length for now (MSB) */ /* This page doesn't include a page header */ /* set parameter log sense data length */ buf[
2] =
len >>
8;
/* log sense length (MSB) */ buf[
3] =
len &
0xff;
/* log sense length (LSB) */ /* Check allocation length */ * We do not check for possible parameters truncation * (alc_len < len) assuming that the target driver works * correctly. Just avoiding overrun. * Copy no more than requested and possible, buffer-wise. /* scsi callback required */ /* Scheduling the callback failed */ * Translate command: Log Select * Not implemented at this time - returns invalid command response. "sata_txlt_log_select\n",
NULL);
* Translate command: Read (various types). * Translated into appropriate type of ATA READ command * Both the device capabilities and requested operation mode are * Following scsi cdb fields are ignored: * rdprotect, dpo, fua, fua_nv, group_number. * If SATA_ENABLE_QUEUING flag is set (in the global SATA HBA framework * enable variable sata_func_enable), the capability of the controller and * capability of a device are checked and if both support queueing, read * request will be translated to READ_DMA_QUEUEING or READ_DMA_QUEUEING_EXT * command rather than plain READ_XXX command. * If SATA_ENABLE_NCQ flag is set in addition to SATA_ENABLE_QUEUING flag and * both the controller and device suport such functionality, the read * request will be translated to READ_FPDMA_QUEUED command. * In both cases the maximum queue depth is derived as minimum of: * HBA capability,device capability and sata_max_queue_depth variable setting. * The value passed to HBA driver is decremented by 1, because only 5 bits are * used to pass max queue depth value, and the maximum possible queue depth * Returns TRAN_ACCEPT or code returned by sata_hba_start() and * appropriate values in scsi_pkt fields. * Extract LBA and sector count from scsi CDB. /* 6-byte scsi read cmd : 0x08 */ /* sec_count 0 will be interpreted as 256 by a device */ /* 10-bytes scsi read command : 0x28 */ /* 12-bytes scsi read command : 0xA8 */ /* 16-bytes scsi read command : 0x88 */ /* Unsupported command */ * Check if specified address exceeds device capacity * For zero-length transfer, emulate good completion of the command * (reasons for rejecting the command were already checked). * No DMA resources were allocated. * Build cmd block depending on the device capability and * requested operation mode. * Do not bother with non-dma mode - we are working only with * devices supporting DMA. * Check if queueing commands should be used and switch * to appropriate command if possible /* Queuing supported by controller and device? */ /* NCQ supported - use FPDMA READ */ }
else /* NCQ nor legacy queuing not supported */ * If queuing, the sector count goes in the features register * and the secount count will contain the tag. /* Set-up maximum queue depth */ * Although NCQ/TCQ is not enabled, untagged queuing * Set-up the maximum untagged queue depth. * Use controller's queue depth from sata_hba_tran. * SATA HBA drivers may ignore this value and rely on * the internal limits.For drivers that do not * ignore untaged queue depth, limit the value to * SATA_MAX_QUEUE_DEPTH (32), as this is the * largest value that can be passed via "sata_txlt_read cmd 0x%2x, lba %llx, sec count %x\n",
/* Need callback function */ /* Transfer command to HBA */ /* Pkt not accepted for execution */ * If execution is non-synchronous, * a callback function will handle potential errors, translate * the response and will do a callback to a target driver. * If it was synchronous, check execution status using the same "synchronous execution status %x\n",
* SATA translate command: Write (various types) * Translated into appropriate type of ATA WRITE command * Both the device capabilities and requested operation mode are * Following scsi cdb fields are ignored: * rwprotect, dpo, fua, fua_nv, group_number. * If SATA_ENABLE_QUEUING flag is set (in the global SATA HBA framework * enable variable sata_func_enable), the capability of the controller and * capability of a device are checked and if both support queueing, write * request will be translated to WRITE_DMA_QUEUEING or WRITE_DMA_QUEUEING_EXT * command rather than plain WRITE_XXX command. * If SATA_ENABLE_NCQ flag is set in addition to SATA_ENABLE_QUEUING flag and * both the controller and device suport such functionality, the write * request will be translated to WRITE_FPDMA_QUEUED command. * In both cases the maximum queue depth is derived as minimum of: * HBA capability,device capability and sata_max_queue_depth variable setting. * The value passed to HBA driver is decremented by 1, because only 5 bits are * used to pass max queue depth value, and the maximum possible queue depth * Returns TRAN_ACCEPT or code returned by sata_hba_start() and * appropriate values in scsi_pkt fields. * Extract LBA and sector count from scsi CDB /* 6-byte scsi read cmd : 0x0A */ /* sec_count 0 will be interpreted as 256 by a device */ /* 10-bytes scsi write command : 0x2A */ /* 12-bytes scsi read command : 0xAA */ /* 16-bytes scsi write command : 0x8A */ /* Unsupported command */ * Check if specified address and length exceeds device capacity * For zero-length transfer, emulate good completion of the command * (reasons for rejecting the command were already checked). * No DMA resources were allocated. * Build cmd block depending on the device capability and * requested operation mode. * Do not bother with non-dma mode- we are working only with * devices supporting DMA. * Check if queueing commands should be used and switch * to appropriate command if possible /* Queuing supported by controller and device? */ /* NCQ supported - use FPDMA WRITE */ }
else /* NCQ nor legacy queuing not supported */ /* Set-up maximum queue depth */ * Although NCQ/TCQ is not enabled, untagged queuing * Set-up the maximum untagged queue depth. * Use controller's queue depth from sata_hba_tran. * SATA HBA drivers may ignore this value and rely on * the internal limits. For drivera that do not * ignore untaged queue depth, limit the value to * SATA_MAX_QUEUE_DEPTH (32), as this is the * largest value that can be passed via "sata_txlt_write cmd 0x%2x, lba %llx, sec count %x\n",
/* Need callback function */ /* Transfer command to HBA */ /* Pkt not accepted for execution */ * If execution is non-synchronous, * a callback function will handle potential errors, translate * the response and will do a callback to a target driver. * If it was synchronous, check execution status using the same "synchronous execution status %x\n",
* Implements SCSI SBC WRITE BUFFER command download microcode option "sata_txlt_write_buffer, mode 0x%x\n",
mode);
* If in interrupt context, reject this packet because it would issue * a synchronous command to HBA. "sata_txlt_write_buffer: rejecting command because " "of interrupt context\n",
NULL);
/* Use synchronous mode */ * The SCSI to ATA translation specification only calls * for WB_DOWNLOAD_MICROCODE_AND_SAVE_MODE. * WB_DOWNLOAD_MICROC_AND_REVERT_MODE is implemented, but * ATA 8 (draft) got rid of download microcode for temp * and it is even optional for ATA 7, so it may be aborted. * WB_DOWNLOAD_MICROCODE_WITH_OFFSET is not implemented as * it is not specified and the buffer offset for SCSI is a 16-bit * value in bytes, but for ATA it is a 16-bit offset in 512 byte * sectors. Thus the offset really doesn't buy us anything. * If and when ATA 8 is stabilized and the SCSI to ATA specification * is revised, this can be revisisted. /* Reject not supported request */ /* Transfer command to HBA */ /* Pkt not accepted for execution */ /* Then we need synchronous check the status of the disk */ /* Download commmand succeed, so probe and identify device */ /* Something went wrong, microcode download command failed */ * We have no device data. Assume no data transfered. * determine dev error reason from error /* No extended sense key - no info available */ /* No extended sense key ? */ /* No extended sense key ? */ /* pkt aborted by an explicit reset from a host */ "sata_txlt_nodata_cmd_completion: " "invalid packet completion reason %d",
/* scsi callback required */ /* scsi callback required */ /* Scheduling the callback failed */ * Re-identify device after doing a firmware download. * Before returning good status, probe device. * Device probing will get IDENTIFY DEVICE data, if possible. * The assumption is that the new microcode is applied by the * device. It is a caller responsibility to verify this. "SATA device at port %d pmport %d -" " default device features could not" " be set. Device may not operate " }
else /* failed - no reason to retry */ * Something went wrong, device probing failed. "Cannot probe device after downloading microcode\n"));
/* Reset device to force retrying the probe. */ * Translate command: Synchronize Cache. * Translates into Flush Cache command for SATA hard disks. * Returns TRAN_ACCEPT or code returned by sata_hba_start() and * appropriate values in scsi_pkt fields. "sata_txlt_synchronize_cache\n",
NULL);
/* Need to set-up a callback function */ /* Transfer command to HBA */ /* Pkt not accepted for execution */ * If execution non-synchronous, it had to be completed * a callback function will handle potential errors, translate * the response and will do a callback to a target driver. * If it was synchronous, check status, using the same "synchronous execution status %x\n",
* Send pkt to SATA HBA driver * This function may be called only if the operation is requested by scsi_pkt, * i.e. scsi_pkt is not NULL. * This function has to be called with cport mutex held. It does release * the mutex when it calls HBA driver sata_tran_start function and * re-acquires it afterwards. * If return value is 0, pkt was accepted, -1 otherwise * rval is set to appropriate sata_scsi_start return value. * Note 1:If HBA driver returns value other than TRAN_ACCEPT, it should not * have called the sata_pkt callback function for this packet. * The scsi callback has to be performed by the caller of this routine. * Note 2: No port multiplier support for now. /* Clear device reset state? */ "sata_hba_start: clearing device reset state\n",
NULL);
"Sata cmd 0x%2x\n",
cmd);
* If sata pkt was accepted and executed in asynchronous mode, i.e. * with the sata callback, the sata_pkt could be already destroyed * by the time we check ther return status from the hba_start() * function, because sata_scsi_destroy_pkt() could have been already * called (perhaps in the interrupt context). So, in such case, there * should be no references to it. In other cases, sata_pkt still * pkt accepted for execution. * If it was executed synchronously, it is already completed * and pkt completion_reason indicates completion status. * Controller detected queue full condition. "sata_hba_start: queue full\n",
NULL);
* detected before pkt execution begun. "SATA port %d pmport %d error\n",
* sata_pkt should be still valid. Since port error is * returned, sata_device content should reflect port * state - it means, that sata address have been changed, * because original packet's sata address refered to a device * Command rejected by HBA as unsupported. It was HBA driver * that rejected the command, command was not sent to "sat_hba_start: cmd 0x%2x rejected " "with SATA_TRAN_CMD_UNSUPPORTED status\n",
cmd);
* Command rejected by HBA because other operation prevents * accepting the packet, or device is in RESET condition. "sata_hba_start: cmd 0x%2x rejected " "because of device reset condition\n",
"sata_hba_start: cmd 0x%2x rejected " "with SATA_TRAN_BUSY status\n",
/* Unrecognized HBA response */ "sata_hba_start: unrecognized HBA response " "to cmd : 0x%2x resp 0x%x",
cmd,
rval));
* If we got here, the packet was rejected. * Check if we need to remember reset state clearing request * Check if device is still configured - it may have * disapeared from the configuration * Restore the flag that requests clearing of * the device reset state, * so the next sata packet may carry it to HBA. * Scsi response setup for invalid LBA * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields. /* scsi callback required */ /* Scheduling the callback failed */ * Analyze device status and error registers and translate them into * appropriate scsi sense codes. * NOTE: non-packet commands only for now /* Information bytes (LBA) need to be set by a caller */ /* ADD HERE: MC error bit handling for ATAPI CD/DVD */ * Extract error LBA from sata_pkt.satapkt_cmd register fields * This is fixed sense format - if LBA exceeds the info field size, * no valid info will be returned (valid bit in extended sense will /* Fill ARQ sense data */ * Emulated SATA Read/Write command completion for zero-length requests. * This request always succedes, so in synchronous mode it always returns * TRAN_ACCEPT, and in non-synchronous mode it may return TRAN_BUSY if the * callback cannot be scheduled. /* scsi callback required - have to schedule it */ /* Scheduling the callback failed */ * Translate completion status of SATA read/write commands into scsi response. * pkt completion_reason is checked to determine the completion status. * Do scsi callback if necessary. * Note: this function may be called also for synchronously executed * This function may be used only if scsi_pkt is non-NULL. /* Temporary buffer was used */ * Something went wrong - analyze return * SATA_PKT_DEV_ERROR is the only case where we may be able to * extract from device registers the failing LBA. * We have problem reporting this cmd LBA * in fixed sense data format, because of * the size of the scsi LBA fields. /* Invalid extended sense info */ /* We may want to handle DEV GONE state as well */ * We have no device data. Assume no data transfered. * determine dev error reason from error /* Unrecovered read error */ "sata_txlt_rw_completion :" "internal error - invalid " /* No extended sense key - no info available */ "sata_txlt_rw_completion: " "invalid packet completion reason"));
/* scsi callback required */ * Translate completion status of non-data commands (i.e. commands returning * pkt completion_reason is checked to determine the completion status. * Do scsi callback if necessary (FLAG_NOINTR == 0) * Note: this function may be called also for synchronously executed * This function may be used only if scsi_pkt is non-NULL. /* Something went wrong */ * We have no device data. Assume no data transfered. * determine dev error reason from error /* No extended sense key - no info available */ /* No extended sense key ? */ /* No extended sense key ? */ /* pkt aborted by an explicit reset from a host */ "sata_txlt_nodata_cmd_completion: " "invalid packet completion reason %d",
/* scsi callback required */ * Build Mode sense R/W recovery page * Build Mode sense caching page - scsi-3 implementation. * Page length distinguishes previous format from scsi-3 format. * buf must have space for 0x12 bytes. * Only DRA (disable read ahead ) and WCE (write cache enable) are changeable. * Most of the fields are set to 0, being not supported and/or disabled /* Saved paramters not supported */ * For now treat current and default parameters as same * That may have to change, if target driver will complain page->
dra =
1;
/* Read Ahead disabled */ page->
rcd =
1;
/* Read Cache disabled */ page->
wce =
1;
/* Write Cache enabled */ /* Changeable parameters */ * Build Mode sense exception cntrl page * Most of the fields are set to 0, being not supported and/or disabled /* Indicate that this is page is saveable */ * We will return the same data for default, current and saved page. * The only changeable bit is dexcpt and that bit is required * by the ATA specification to be preserved across power cycles. * Most of the fields are set to 0, being not supported and/or disabled /* default paramters not supported */ /* Saved and current are supported and are identical */ /* Word 83 indicates if feature is supported */ /* If feature is not supported */ /* Word 94 inidicates the value */ /* Word 83 indicates if the feature is supported */ * Build Mode sense power condition page * Process mode select caching page 8 (scsi3 format only). * Read Ahead (same as read cache) and Write Cache may be turned on and off * if these features are supported by the device. If these features are not * supported, quietly ignore them. * This function fails only if the SET FEATURE command sent to * the device fails. The page format is not varified, assuming that the * target driver operates correctly - if parameters length is too short, * Two command may be sent if both Read Cache/Read Ahead and Write Cache * setting have to be changed. * SET FEATURE command is executed synchronously, i.e. we wait here until * it is completed, regardless of the scsi pkt directives. * Note: Mode Select Caching page RCD and DRA bits are tied together, i.e. * changing DRA will change RCD. * More than one SATA command may be executed to perform operations specified * by mode select pages. The first error terminates further execution. * Operations performed successully are not backed-up in such case. * Return SATA_SUCCESS if operation succeeded, SATA_FAILURE otherwise. * If operation resulted in changing device setup, dmod flag should be set to * one (1). If parameters were not changed, dmod flag should be set to 0. * Upon return, if operation required sending command to the device, the rval * should be set to the value returned by sata_hba_start. If operation * did not require device access, rval should be set to TRAN_ACCEPT. * The pagelen should be set to the length of the page. * This function has to be called with a port mutex held. * Returns SATA_SUCCESS if operation was successful, SATA_FAILURE otherwise. int wce,
dra;
/* Current settings */ /* Verify parameters length. If too short, drop it */ * We can manipulate only write cache and read ahead * None of the features is supported - ignore /* Current setting of Read Ahead (and Read Cache) */ dra = 0;
/* 0 == not disabled */ /* Current setting of Write Cache */ * Need to flip some setting * Set-up Internal SET FEATURES command(s) /* Need to flip read ahead setting */ /* Disable read ahead / read cache */ /* Enable read ahead / read cache */ /* Transfer command to HBA */ * Pkt not accepted for execution. /* Note that the packet is not removed, so it could be re-used */ /* Need to flip Write Cache setting */ /* Disable write cache */ /* Transfer command to HBA */ * Pkt not accepted for execution. * Process mode select informational exceptions control page 0x1c * The only changeable bit is dexcpt (disable exceptions). * MRIE (method of reporting informational exceptions) must be * This page applies to informational exceptions that report * additional sense codes with the ADDITIONAL SENSE CODE field set to 5Dh * (e.g.,FAILURE PREDICTION THRESHOLD EXCEEDED) or 0Bh (e.g., WARNING_). * Informational exception conditions occur as the result of background scan * errors, background self-test errors, or vendor specific events within a * logical unit. An informational exception condition may occur asynchronous * Returns: SATA_SUCCESS if operation succeeded, SATA_FAILURE otherwise. * If operation resulted in changing device setup, dmod flag should be set to * one (1). If parameters were not changed, dmod flag should be set to 0. * Upon return, if operation required sending command to the device, the rval * should be set to the value returned by sata_hba_start. If operation * did not require device access, rval should be set to TRAN_ACCEPT. * The pagelen should be set to the length of the page. * This function has to be called with a port mutex held. * Returns SATA_SUCCESS if operation was successful, SATA_FAILURE otherwise. * Cannot be called in the interrupt context. /* Verify parameters length. If too short, drop it */ /* If already in the state requested, we are done */ /* Build SMART_ENABLE or SMART_DISABLE command */ /* Transfer command to HBA */ * Pkt not accepted for execution. *
dmod =
1;
/* At least may have been modified */ /* Packet did not complete successfully */ * Process mode select acoustic management control page 0x30 * This function has to be called with a port mutex held. * Returns SATA_SUCCESS if operation was successful, SATA_FAILURE otherwise. * Cannot be called in the interrupt context. /* If parmlen is too short or the feature is not supported, drop it */ * We can enable and disable acoustice management and * set the acoustic management level. * Set-up Internal SET FEATURES command(s) }
else {
/* disabling acoustic management */ /* Transfer command to HBA */ * Pkt not accepted for execution. * sata_build_lsense_page0() is used to create the * SCSI LOG SENSE page 0 (supported log pages) * Currently supported pages are 0, 0x10, 0x2f and 0x30 * (supported log pages, self-test results, informational exceptions * and Sun vendor specific ATA SMART data). * Takes a sata_drive_info t * and the address of a buffer * in which to create the page information. * Returns the number of bytes valid in the buffer. * sata_build_lsense_page_10() is used to create the * SCSI LOG SENSE page 0x10 (self-test results) * Takes a sata_drive_info t * and the address of a buffer * in which to create the page information as well as a sata_hba_inst_t *. * Returns the number of bytes valid in the buffer. * Note: Self test and SMART data is accessible in device log pages. * The log pages can be accessed by SMART READ/WRITE LOG (up to 255 sectors * of data can be transferred by a single command), or by the General Purpose * Logging commands (GPL) READ LOG EXT and WRITE LOG EXT (up to 65,535 sectors * - approximately 33MB - can be transferred by a single command. * The SCT Command response (either error or command) is the same for both * the SMART and GPL methods of issuing commands. * This function uses READ LOG EXT command when drive supports LBA48, and * SMART READ command otherwise. * Since above commands are executed in a synchronous mode, this function * should not be called in an interrupt context. --
index;
/* Correct for 0 origin */ /* If this is an unused entry, we are done */ /* Broken firmware on some disks */ code = 0;
/* unspecified */ }
else {
/* No bad block address */ --
index;
/* Back up to previous entry */ --
index;
/* Correct for 0 origin */ code = 0;
/* unspecified */ }
else {
/* No block address */ --
index;
/* back up to previous entry */ * sata_build_lsense_page_2f() is used to create the * SCSI LOG SENSE page 0x2f (informational exceptions) * Takes a sata_drive_info t * and the address of a buffer * in which to create the page information as well as a sata_hba_inst_t *. * Returns the number of bytes valid in the buffer. * Because it invokes function(s) that send synchronously executed command * to the HBA, it cannot be called in the interrupt context. /* Now get the SMART status w.r.t. threshold exceeded */ case -
1:
/* failed to get data */ /* Now get the temperature */ * sata_build_lsense_page_30() is used to create the * SCSI LOG SENSE page 0x30 (Sun's vendor specific page for ATA SMART data). * Takes a sata_drive_info t * and the address of a buffer * in which to create the page information as well as a sata_hba_inst_t *. * Returns the number of bytes valid in the buffer. /* Now do the SMART READ DATA */ /* ************************** ATAPI-SPECIFIC FUNCTIONS ********************** */ * Start command for ATAPI device. * This function processes scsi_pkt requests. * Now CD/DVD, tape and ATAPI disk devices are supported. * Most commands are packet without any translation into Packet Command. * Some may be trapped and executed as SATA commands (not clear which one). * Returns TRAN_ACCEPT if command is accepted for execution (or completed * Returns other TRAN_XXXX codes if command is not accepted or completed * (see return values for sata_hba_start()). * Inquiry cdb format differs between transport version 2 and 3. * However, the transport version 3 devices that were checked did not adhere * to the specification (ignored MSB of the allocation length). Therefore, * the transport version is not checked, but Inquiry allocation length is * truncated to 255 bytes if the original allocation length set-up by the * target driver is greater than 255 bytes. * ATAPI device executes some ATA commands in addition to those * commands sent via PACKET command. These ATA commands may be * executed by the regular SATA translation functions. None needs * Commands sent via PACKET command include: * MMC command set for ATAPI CD/DVD device * SSC command set for ATAPI TAPE device * SBC command set for ATAPI disk device /* Check the size of cdb */ "sata: invalid ATAPI cdb length %d",
* SATA_DIR_NODATA_XFER - is set by * sata_txlt_generic_pkt_info(). * Set up ATAPI packet command. /* Copy cdb into sata_cmd */ /* See note in the command header */ "%02x %02x %02x %02x %02x %02x %02x %02x " "%2x %02x %02x %02x %02x %02x %02x %02x",
p[0], p[
1], p[
2], p[
3], p[
4], p[
5], p[
6], p[
7],
p[
8], p[
9], p[
10], p[
11], p[
12], p[
13], p[
14], p[
15]);
* Preset request sense data to NO SENSE. * If there is no way to get error information via Request Sense, * the packet request sense data would not have to be modified by HBA, * but it could be returned as is. /* Need callback function */ /* Transfer command to HBA */ /* Pkt not accepted for execution */ * If execution is non-synchronous, * a callback function will handle potential errors, translate * the response and will do a callback to a target driver. * If it was synchronous, use the same framework callback to check "synchronous execution status %x\n",
* ATAPI Packet command completion. * Failure of the command passed via Packet command are considered device * error. SATA HBA driver would have to retrieve error data (via Request * Sense command delivered via error retrieval sata packet) and copy it * to satacmd_rqsense array. From there, it is moved into scsi pkt sense data. /* Temporary buffer was used */ * Something went wrong - analyze return * pkt_reason should be CMD_CMPLT for DEVICE ERROR. * Under this condition ERR bit is set for ATA command, * and CHK bit set for ATAPI command. * Please check st_intr & sdintr about how pkt_reason * We may not have ARQ data if there was a double * error. But sense data in sata packet was pre-set * with NO SENSE so it is valid even if HBA could * not retrieve a real sense data. * Just copy this sense data into scsi pkt sense area. "sata_txlt_atapi_completion: %02x\n" "RQSENSE: %02x %02x %02x %02x %02x %02x " " %02x %02x %02x %02x %02x %02x " " %02x %02x %02x %02x %02x %02x\n",
* We have no device data. * Need to check if HARDWARE_ERROR/ * TIMEOUT_ON_LOGICAL_UNIT 4/3E/2 would be more /* Should we set key COMMAND_ABPRTED? */ * May be we should set Unit Attention / * Reset. Perhaps the same should be "sata_txlt_atapi_completion: " "invalid packet completion reason"));
/* scsi callback required */ * Set up error retrieval sata command for ATAPI Packet Command error data * Returns SATA_SUCCESS when data buffer is allocated and packet set-up, * returns SATA_FAILURE otherwise. * Allocate dma-able buffer error data. * Buffer allocation will take care of buffer alignment and other DMA "sata_get_err_retrieval_pkt: " "cannot allocate buffer for error data",
NULL);
/* Operation modes are up to the caller */ /* Synchronous mode, no callback - may be changed by the caller */ * Set-up acdb. Request Sense CDB (packet command content) is * not in DMA-able buffer. Its handling is HBA-specific (how * it is transfered into packet FIS). /* Following zeroing of pad bytes may not be necessary */ * Set-up pointer to the buffer handle, so HBA can sync buffer * before accessing it. Handle is in usual place in translate struct. * Preset request sense data to NO SENSE. * Here it is redundant, only for a symetry with scsi-originated * packets. It should not be used for anything but debugging. * Set-up ATAPI packet command. * Data transfer direction has to be set-up in sata_cmd structure prior to * We want all data to be transfered via DMA. * But specify it only if drive supports DMA and DMA mode is * selected - some drives are sensitive about it. * Hopefully it wil work for all drives.... * Features register requires special care for devices that use * Serial ATA bridge - they need an explicit specification of * the data transfer direction for Packet DMA commands. * Setting this bit is harmless if DMA is not used. * Many drives do not implement word 80, specifying what ATA/ATAPI * We are arbitrarily following the latest SerialATA 2.6 spec, * which uses ATA/ATAPI 6 specification for Identify Data, unless * Specification of major version is valid and version 7 * is supported. It does automatically imply that all * spec features are supported. For now, we assume that * DMADIR setting is valid. ATA/ATAPI7 spec is incomplete. /* Display 18 bytes of Inquiry data */ p[0], p[
1], p[
2], p[
3], p[
4], p[
5], p[
6], p[
7]);
p[0], p[
1], p[
2], p[
3], p[
4], p[
5], p[
6], p[
7]);
"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
p[0], p[
1], p[
2], p[
3], p[
4], p[
5], p[
6], p[
7],
p[
8], p[
9], p[
10], p[
11], p[
12], p[
13], p[
14], p[
15]);
"%c %c %c %c %c %c %c %c",
p[0], p[
1], p[
2], p[
3], p[
4], p[
5], p[
6], p[
7],
p[
8], p[
9], p[
10], p[
11], p[
12], p[
13], p[
14], p[
15]);
* Fetch inquiry data from ATAPI device * Returns SATA_SUCCESS if operation was successfull, SATA_FAILURE otherwise. * inqb pointer does not point to a DMA-able buffer. It is a local buffer * where the caller expects to see the inquiry data. /* address is needed now */ /* scsi_inquiry size buffer */ "sata_get_atapi_inquiry_data: " "cannot allocate data buffer"));
/* Use synchronous mode */ /* Issue inquiry command - 6 bytes cdb, data transfer, read */ /* we have to be carefull about the disapearing device */ * Set-up acdb. This works for atapi transport version 2 and later. /* Transfer command to HBA */ /* Pkt not accepted for execution */ "sata_get_atapi_inquiry_data: " "Packet not accepted for execution - ret: %02x",
rval);
"sata_get_atapi_inquiry_data: " "Packet completed successfully - ret: %02x",
rval);
* Sync buffer. Handle is in usual place in translate * Normal completion - copy data into caller's buffer * Something went wrong - analyze return - check rqsense data * ARQ data hopefull show something other than NO SENSE "ATAPI packet completion reason: %02x\n" "RQSENSE: %02x %02x %02x %02x %02x %02x\n" " %02x %02x %02x %02x %02x %02x\n" " %02x %02x %02x %02x %02x %02x",
"sata_get_atapi_inquiry_data: " "packet reason: port error",
NULL);
"sata_get_atapi_inquiry_data: " "packet reason: timeout",
NULL);
"sata_get_atapi_inquiry_data: " "packet reason: aborted",
NULL);
"sata_get_atapi_inquiry_data: " "packet reason: reset\n",
NULL);
"sata_get_atapi_inquiry_data: " "invalid packet reason: %02x\n",
* Test ATAPI packet command. * Single threaded test: send packet command in synch mode, process completion "sata_test_atapi_packet_command: " "no device info for cport %d",
/* address is needed now */ "sata_test_atapi_packet_command: " "cannot allocate data buffer");
/* Use synchronous mode */ /* Synchronous mode, no callback - may be changed by the caller */ /* Issue inquiry command - 6 bytes cdb, data transfer, read */ /* Transfer command to HBA */ /* Pkt not accepted for execution */ "sata_test_atapi_packet_command: " "Packet not accepted for execution - ret: %02x",
rval);
* Sync buffer. Handle is in usual place in translate struct. "sata_test_atapi_packet_command: " "Packet completed successfully");
* Normal completion - show inquiry data * Something went wrong - analyze return - check rqsense data * ARQ data hopefull show something other than NO SENSE "ATAPI packet completion reason: %02x\n" "RQSENSE: %02x %02x %02x %02x %02x %02x " " %02x %02x %02x %02x %02x %02x " " %02x %02x %02x %02x %02x %02x\n",
"sata_test_atapi_packet_command: " "packet reason: port error\n");
"sata_test_atapi_packet_command: " "packet reason: timeout\n");
"sata_test_atapi_packet_command: " "packet reason: aborted\n");
"sata_test_atapi_packet_command: " "packet reason: reset\n");
"sata_test_atapi_packet_command: " "invalid packet reason: %02x\n",
/* ************************** LOCAL HELPER FUNCTIONS *********************** */ * Validate sata_tran info * SATA_FAILURE returns if structure is inconsistent or structure revision * does not match one used by the framework. * Returns SATA_SUCCESS if sata_hba_tran has matching revision and contains * required function pointers. * Returns SATA_FAILURE otherwise. * SATA_TRAN_HBA_REV is the current (highest) revision number "sata: invalid sata_hba_tran version %d for driver %s",
"sata: inconsistent sata_tran_hba_dip " * Remove HBA instance from sata_hba_list. "unknown HBA instance\n");
* Probe all SATA ports of the specified HBA instance. * The assumption is that there are no target and attachment point minor nodes * created by the boot subsystems, so we do not need to prune device tree. * This function is called only from sata_hba_attach(). It does not have to * be protected by controller mutex, because the hba_attached flag is not set * yet and no one would be touching this HBA instance other than this thread. * Determines if port is active and what type of the device is attached * (if any). Allocates necessary structures for each port. * An AP (Attachement Point) node is created for each SATA device port even * when there is no device attached. * Probe controller ports first, to find port status and * any port multiplier attached. /* allocate cport structure */ * Regardless if a port is usable or not, create "cannot create SATA attachment point for port %d",
/* Something went wrong? Fail the port */ * There is some device attached. * Allocate device info structure * Plugged device was not correctly identified. * Retry, within a SATA_DEV_IDENTIFY_TIMEOUT /* Probe Port Multiplier ports */ /* Create an attachment point */ "cannot create SATA attachment " "point for port %d pmult port %d",
/* sata_update_port_info() */ /* Port multipliers cannot be chained */ * There is something attached to Port * Allocate device info structure * Plugged device was not correctly * identified. Retry, within the * SATA_DEV_IDENTIFY_TIMEOUT * Add SATA device for specified HBA instance & port (SCSI target * This function is called (indirectly) only from sata_hba_attach(). * A target node is created when there is a supported type device attached, * but may be removed if it cannot be put online. * This function cannot be called from an interrupt context. * ONLY DISK TARGET NODES ARE CREATED NOW * Returns SATA_SUCCESS when port/device was fully processed, SATA_FAILURE when * device identification failed - adding a device could be retried. * Some device is attached to a controller port. * We rely on controllers distinquishing between no-device, * attached port multiplier and other kind of attached device. * We need to get Identify Device data and determine * positively the dev type before trying to attach * Could not determine device type or * a device is not supported. * Degrade this device to unknown. * Initialize device to the desired state. Even if it * fails, the device will still attach but syslog "SATA device at port %d - " "default device features could not be set." " Device may not operate as expected.",
* Attaching target node failed. * We retain sata_drive_info structure... /* This must be Port Multiplier type */ "unrecognized dev type %x",
* Could not determine device type. * Degrade this device to unknown. * Initialize device to the desired state. * Even if it fails, the device will still * attach but syslog will show the warning. "SATA device at port %d pmport %d - " "default device features could not be set." " Device may not operate as expected.",
* Attaching target node failed. * We retain sata_drive_info structure... * Create scsi target node for attached device, create node properties and * The node could be removed if the device onlining fails. * A dev_info_t pointer is returned if operation is successful, NULL is * No port multiplier support. "sata_create_target_node: no sdinfo for target %x",
* create or get scsi inquiry data, expected by * scsi_hba_nodename_compatible_get() * SATA hard disks get Identify Data translated into Inguiry Data. * ATAPI devices respond directly to Inquiry request. }
else {
/* Assume supported ATAPI device */ * Save supported ATAPI transport version /* determine the node name and compatible */ "cannot determine nodename for target %d\n",
"sata_create_target_node: no compatible name\n");
/* if nodename can't be determined, log error and exit */ "sata_create_target_node: cannot determine nodename " * Create scsi target node "updating device_type prop failed %d",
rval));
* Create target node properties: target & lun "updating target prop failed %d",
rval));
"updating target prop failed %d",
rval));
"sata_create_target_node: variant atapi " "property could not be created: %d",
rval));
/* decorate the node with compatible */ "sata_create_target_node: FAIL compatible props cdip 0x%p",
* Now, try to attach the driver. If probing of the device fails, * the target node may be removed /* target node was removed - are we sure? */ "node removal failed %d",
rval));
"cannot create target node for SATA device at port %d",
* Re-probe sata port, check for a device and attach info * structures when necessary. Identify Device data is fetched, if possible. * Assumption: sata address is already validated. * SATA_SUCCESS is returned if port is re-probed sucessfully, regardless of * the presence of a device and its type. * flag arg specifies that the function should try multiple times to identify * device type and to initialize it, or it should return immediately on failure. * SATA_DEV_IDENTIFY_RETRY - retry * SATA_DEV_IDENTIFY_NORETRY - no retry * SATA_FAILURE is returned if one of the operations failed. * This function cannot be called in interrupt context - it may sleep. * NOte: Port multiplier is not supported yet, although there may be some * pieces of code referencing to it. /* We only care about host sata cport for now */ * We are re-probing port with a previously attached device. * Save previous device type and settings. "SATA port %d probing failed",
* update sata port state and set device type * Sanity check - Port is active? Is the link active? * Is there any device attached? * Port in non-usable state or no link active/no device. * Free info structure if necessary (direct attached drive /* Add here differentiation for device attached or not */ * If we are re-probing the port, there may be * sata_drive_info structure attached * (or sata_pm_info, if PMult is supported). * There is no device, so remove device info structure, * Only direct attached drive is considered now, until * port multiplier is supported. If the previously * attached device was a port multiplier, we would need * to take care of devices attached beyond the port * There is some device attached, but there is * no sata_drive_info structure - allocate one * Recheck, that the port state did not change when we * Port is not in ready state, we * cannot attach a device. * Since we are adding device, presumably new one, * indicate that it should be initalized, * as well as some internal framework states). * The device is a port multiplier - not handled now. * Figure out what kind of device we are really * dealing with. Failure of identifying device does not fail this * If we are dealing with the same type of a device as before, * restore its settings flags. /* Set initial device features, if necessary */ /* else we will retry if retry was asked for */ * If there was some device info before we probe the device, * restore previous device setting, so we can retry from scratch * later. Providing, of course, that device has not disapear * during probing process. * A device was not successfully identified or initialized. * Track retry time for device identification. /* else no more retries */ * Setting drive features have failed, but * because the drive is still accessible, * keep it and emit a warning message. "SATA device at port %d - desired " "drive features could not be set. " "Device may not operate as expected.",
* Specified device is initialized to a default state. * Returns SATA_SUCCESS if all device features are set successfully, * SATA_RETRY if device is accessible but device features were not set * successfully, and SATA_FAILURE otherwise. /* Determine current data transfer mode */ /* DMA supported, not no DMA transfer mode is selected !? */ * Initialize write cache mode. * The default write cache setting for SATA HDD is provided by sata_write_cache * static variable. ATAPI CD/DVDs devices have write cache default is * determined by sata_atapicdvd_write_cache static variable. * ATAPI tape devices have write cache default is determined by * sata_atapitape_write_cache static variable. * ATAPI disk devices have write cache default is determined by * sata_atapidisk_write_cache static variable. * any other value - current drive setting * Although there is not reason to disable write cache on CD/DVD devices, * tape devices and ATAPI disk devices, the default setting control is provided * for the maximun flexibility. * In the future, it may be overridden by the * disk-write-cache-enable property setting, if it is defined. * Returns SATA_SUCCESS if all device features are set successfully, * SATA_FAILURE otherwise. * When sata_write_cache value is not 0 or 1, * a current setting of the drive's write cache is used. * When sata_atapicdvd_write_cache value is not 0 or 1, * a current setting of the drive's write cache is used. * When sata_atapitape_write_cache value is not 0 or 1, * a current setting of the drive's write cache is used. * When sata_atapidisk_write_cache value is not 0 or 1, * a current setting of the drive's write cache is used. * Specified cport, pmport and qualifier has to match * passed sata_scsi configuration info. * The presence of an attached device is not verified. * Returns 0 when address is valid, -1 otherwise. * SCSI target address is translated into SATA cport/pmport and compared * with a controller port/device configuration. LUN has to be 0. * Returns 0 if a scsi target refers to an attached device, * returns 1 if address is valid but device is not attached, * returns -1 if bad address or device is of an unsupported type. * Upon return sata_device argument is set. rval = -
1;
/* Invalid address */ rval =
1;
/* Valid sata address */ "sata_validate_scsi_address: no valid target %x lun %x",
* Find dip corresponding to passed device number * Returns NULL if invalid device number is passed or device cannot be found, * Returns dip is device is found. * This function issues Identify Device command and initializes local * sata_drive_info structure if the device can be identified. * The device type is determined by examining Identify Device * If the sata_hba_inst has linked drive info structure for this * device address, the Identify Device data is stored into sata_drive_info * structure linked to the port info structure. * sata_device has to refer to the valid sata port(s) for HBA described * by sata_hba_inst structure. * SATA_SUCCESS if device type was successfully probed and port-linked * drive info structure was updated; * SATA_FAILURE if there is no device, or device was not probed * SATA_RETRY if device probe can be retried later. * If a device cannot be identified, sata_device's dev_state and dev_type * fields are set to unknown. * There are no retries in this function. Any retries should be managed by /* Get pointer to port-linked sata device info structure */ * Need to issue both types of identify device command and * determine device type by examining retreived data/status. * First, ATA Identify Device. /* We may try to check for ATAPI device */ * HBA supports ATAPI - try to issue Identify Packet * Got something responding positively to ATA Identify Device * or to Identify Packet Device cmd. * Save last used device type. /* save device info, if possible */ * Copy drive info into the port-linked drive info structure. else /* SATA_ADDR_DPMPORT */ * It may be SATA_RETRY or SATA_FAILURE return. * Looks like we cannot determine the device type at this time. * Get pointer to sata_drive_info structure. * The sata_device has to contain address (cport, pmport and qualifier) for * specified sata_scsi structure. * Returns NULL if device address is not valid for this HBA configuration. * Otherwise, returns a pointer to sata_drive_info structure. * This function should be called with a port mutex held. /* Port not probed yet */ /* Request for a device on a controller port */ /* Port multiplier attached */ /* we should not get here */ * Send Identify Device command to SATA HBA driver. * If command executes successfully, update sata_drive_info structure pointed * to by sdinfo argument, including Identify Device data. * If command fails, invalidate data in sata_drive_info. * Cannot be called from interrupt level. * SATA_SUCCESS if the device was identified as a supported device, * SATA_RETRY if the device was not identified but could be retried, * SATA_FAILURE if the device was not identified and identify attempt /* fetch device identify data */ /* Set the correct device type */ /* Non-LBA disk. Too bad... */ "SATA disk device at port %d does not support LBA",
/* Left for historical reason */ * Some initial version of SATA spec indicated that at least * UDMA mode 4 has to be supported. It is not metioned in * SerialATA 2.6, so this restriction is removed. /* Check for Ultra DMA modes 6 through 0 being supported */ for (i =
6; i >= 0; --i) {
* At least UDMA 4 mode has to be supported. If mode 4 or * higher are not supported by the device, fail this /* No required Ultra DMA mode supported */ "SATA disk device at port %d does not support UDMA " "mode 4 or higher required, %d supported", i));
/* Invalidate sata_drive_info ? */ "Unsupported SATA device type (cfg 0x%x) at ",
* Some drives do not implement serial number and may * violate the spec by providing spaces rather than zeros * in serial number field. Scan the buffer to detect it. for (i =
14; i >=
2; i--) {
"?\tATA/ATAPI-%d supported, majver 0x%x minver 0x%x\n",
"Supported queue depth %d",
* sata_save_drive_settings extracts current setting of the device and stores * it for future reference, in case the device setup would need to be restored * after the device reset. * For all devices read ahead and write cache settings are saved, if the * device supports these features at all. * For ATAPI devices the Removable Media Status Notification setting is saved. /* Current setting of Read Ahead (and Read Cache) */ /* Current setting of Write Cache */ * sata_check_capacity function determines a disk capacity * and addressing mode (LBA28/LBA48) by examining a disk identify device data. * NOTE: CHS mode is not supported! If a device does not support LBA, * this function is not called. * Returns device capacity in number of blocks, i.e. largest addressable LBA+1 /* Capacity valid only for LBA-addressable disk devices */ /* LBA48 mode supported and enabled */ for (i =
3; i >= 0; --i) {
* Allocate consistent buffer for DMA transfer * Cannot be called from interrupt level or with mutex held - it may sleep. * Returns pointer to allocated buffer structure, or NULL if allocation failed. /* Allocate DMA resources for this buffer */ * We use a local version of the dma_attr, to account * for a device addressing limitations. * sata_adjust_dma_attr() will handle sdinfo == NULL which * will cause dma attributes to be adjusted to a lowest * Release local buffer (consistent buffer for DMA transfer) allocated * via sata_alloc_local_buffer(). * Pkt structure version and embedded strcutures version are initialized. * sata_pkt and sata_pkt_txlate structures are cross-linked. * Since this may be called in interrupt context by sata_scsi_init_pkt, * callback argument determines if it can sleep or not. * Hence, it should not be called from interrupt context. * If successful, non-NULL pointer to a sata pkt is returned. * Upon failure, NULL pointer is returned. "sata_pkt_alloc: failed"));
* Free sata pkt allocated via sata_pkt_alloc() * SCSI cmds block count is up to 24 bits, SATA cmd block count vary * from 8 bits to 16 bits, depending on a command being used. * Limiting max block count arbitrarily to 256 for all read/write * commands may affects performance, so check both the device and * controller capability before adjusting dma attributes. /* Copy original attributes */ * Things to consider: device addressing capability, * "excessive" controller DMA capabilities. * no device info - use default limits then. * 16-bit sector count may be used - we rely on * the assumption that only read and write cmds * will request more than 256 sectors worth of data * 8-bit sector count will be used - default limits * Adjust controler dma attributes, if necessary * Allocate DMA resources for the buffer * This function handles initial DMA resource allocation as well as * DMA window shift and may be called repeatedly for the same DMA window * until all DMA cookies in the DMA window are processed. * To guarantee that there is always a coherent set of cookies to process * by SATA HBA driver (observing alignment, device granularity, etc.), * the number of slots for DMA cookies is equal to lesser of a number of * cookies in a DMA window and a max number of scatter/gather entries. * Returns DDI_SUCCESS upon successful operation. * Return failure code of a failing command or DDI_FAILURE when * internal cleanup failed. * No DMA resources allocated so far - this is a first call "sata_dma_buf_setup: no buf DMA resources %x",
* Check buffer alignment and size against dma attributes * Consider dma_attr_align only. There may be requests * with the size lower than device granularity, but they * is necessary. The dma_attr_minxfer theoretically should * be considered, but no HBA driver is checking it. }
else {
/* Buffer is not aligned */ /* Check id sleeping is allowed */ "mis-aligned buffer: addr=0x%p, cnt=%lu",
* CPU will need to access data in the buffer * (for copying) so map it. /* Buffer may be padded by ddi_dma_mem_alloc()! */ "buf dma mem alloc failed %x\n",
rval);
* This will require special handling, because * DMA cookies will be based on the temporary * buffer size, not the original buffer * b_bcount, so the residue may have to * be counted differently. "sata_dma_buf_setup: bp size %x != " * Write operation - copy data into * an aligned temporary buffer. Buffer will be * synced for device by ddi_dma_addr_bind_handle "sata_dma_buf_setup: DMA Partial Map\n",
NULL);
* Retrieve number of DMA windows for this request. "sata_dma_buf_setup: numwin failed\n"));
"sata_dma_buf_setup: windows: %d, cookies: %d\n",
"sata_dma_buf_setup: windows: 1 " "sata_dma_buf_setup: buf dma handle binding " * DMA setup is reused. Check if we need to process more * cookies in current window, or to get next window, if any. * All cookies from current DMA window were processed. /* No more windows! End of request! */ /* What to do? - panic for now */ /* There better be at least one DMA cookie outstanding */ /* The default cookie slot was used in previous run */ * Processing a new DMA window - set-up dma cookies list. * We may reuse previously allocated cookie array if it is * New DMA window contains more cookies than * the previous one. We need larger cookie list - free * Calculate lesser of number of cookies in this * DMA window and number of s/g entries. /* Allocate new dma cookie array if necessary */ /* Only one cookie - no need for a list */ * More than one cookie - try to allocate space. "sata_dma_buf_setup: cookie list " "allocation failed\n",
NULL);
* We could not allocate space for * neccessary number of dma cookies in * this window, so we fail this request. * Next invocation would try again to * allocate space for cookie list. * Note:Packet residue was not modified. * Fetch DMA cookies into cookie list in sata_pkt_txlate. * First cookie was already fetched. "sata_dma_buf_setup: sliding within DMA window, " "cur cookie %d, total cookies %d\n",
* Not all cookies from the current dma window were used because * There is no need to re-size the list - it was set at * optimal size, or only default entry is used (s/g = 1). * Since we are processing remaining cookies in a DMA window, * there may be less of them than the number of entries in the * current dma cookie list. /* Fetch the next batch of cookies */ /* Point sata_cmd to the cookie list */ /* Remember number of DMA cookies passed in sata packet */ * Temporary DMA buffer has been padded by * This requires special handling, because DMA cookies are * based on the temporary buffer size, not the b_bcount, * and we have extra bytes to transfer - but the packet * residue has to stay correct because we will copy only * the requested number of bytes. * Common routine for releasing DMA resources * Intermediate DMA buffer was allocated. * Free allocated buffer and associated access handle. * Free DMA resources - cookies and handles /* ASSERT(spx->txlt_dma_cookie_list != NULL); */ * Used by the HBA driver to release DMA resources that it does not use. * Fetch Device Identify data. * Send DEVICE IDENTIFY or IDENTIFY PACKET DEVICE (depending on a device type) * command to a device and get the device identify data. * The device_info structure has to be set to device type (for selecting proper * device identify command). * SATA_SUCCESS if cmd succeeded * SATA_RETRY if cmd was rejected and could be retried, * SATA_FAILURE if cmd failed and should not be retried (port error) * Cannot be called in an interrupt context. /* address is needed now */ * Allocate buffer for Identify Data return data "sata_fetch_device_identify_data: " "cannot allocate buffer for ID"));
/* Synchronous mode, no callback */ /* Build Identify Device cmd in the sata_pkt */ /* Identify Packet Device cmd */ /* Identify Device cmd - mandatory for all other devices */ /* Send pkt to SATA HBA driver */ "SATA disk device at port %d - " /* Update sata_drive_info */ * Retrieve capacity (disks only) and addressing mode * For ATAPI devices one would have to issue * Get Capacity cmd for media capacity. Not here. * Check what cdb length is supported /* Setup supported features flags */ /* Check for SATA GEN and NCQ support */ /* Adjust according to controller capabilities */ /* Adjust according to global queue depth limit */ * Woops, no Identify Data. /* Free allocated resources */ * Some devices may not come-up with default DMA mode (UDMA or MWDMA). * UDMA mode is checked first, followed by MWDMA mode. * set correctly, so this function is setting it to the highest supported level. * Older SATA spec required that the device supports at least DMA 4 mode and * UDMA mode is selected. It is not mentioned in SerialATA 2.6, so this * restriction has been removed. * Returns SATA_SUCCESS if proper DMA mode is selected or no DMA is supported. * Returns SATA_FAILURE if proper DMA mode could not be selected. * NOTE: This function should be called only if DMA mode is supported. /* Find highest Ultra DMA mode supported */ /* Left for historical reasons */ * Some initial version of SATA spec indicated that at least * UDMA mode 4 has to be supported. It is not mentioned in * SerialATA 2.6, so this restriction is removed. /* Find UDMA mode currently selected */ for (i =
6; i >= 0; --i) {
/* Find highest MultiWord DMA mode supported */ /* Find highest MultiWord DMA mode selected */ for (i =
2; i >= 0; --i) {
* Set DMA mode via SET FEATURES COMMAND. * Prepare packet for SET FEATURES COMMAND. "sata_set_dma_mode: could not set DMA mode %",
mode));
/* Synchronous mode, no callback, interrupts */ /* Transfer command to HBA */ /* Pkt execution failed */ /* Free allocated resources */ * Set device caching mode. * One of the following operations should be specified: * SATAC_SF_ENABLE_READ_AHEAD * SATAC_SF_DISABLE_READ_AHEAD * SATAC_SF_ENABLE_WRITE_CACHE * SATAC_SF_DISABLE_WRITE_CACHE * If operation fails, system log messgage is emitted. * Returns SATA_SUCCESS when the operation succeeds, SATA_RETRY if * command was sent but did not succeed, and SATA_FAILURE otherwise. /* Prepare packet for SET FEATURES COMMAND */ /* Synchronous mode, no callback, interrupts */ /* Transfer command to HBA */ /* Pkt execution failed */ infop =
"enabling read ahead failed";
infop =
"disabling read ahead failed";
infop =
"enabling write cache failed";
infop =
"disabling write cache failed";
/* Free allocated resources */ * If operation fails, system log messgage is emitted. * Returns SATA_SUCCESS when the operation succeeds, SATA_FAILURE otherwise. /* Prepare packet for SET FEATURES COMMAND */ /* Synchronous mode, no callback, interrupts */ /* Transfer command to HBA */ /* Pkt execution failed */ infop =
"disabling Removable Media Status " infop =
"enabling Removable Media Status " /* Free allocated resources */ * Update state and copy port ss* values from passed sata_device structure. * sata_address is validated - if not valid, nothing is changed in sata_scsi * SATA_PSTATE_SHUTDOWN in port state is not reset to 0 by this function * regardless of the state in device argument. * Port mutex should be held while calling this function. /* Preserve SATA_PSTATE_SHUTDOWN flag */ /* Preserve SATA_PSTATE_SHUTDOWN flag */ * Extract SATA port specification from an IOCTL argument. * This function return the port the user land send us as is, unless it * cannot retrieve port spec, then -1 is returned. * Note: Only cport - no port multiplier port. /* Extract port number from nvpair in dca structure */ "sata_get_port_num: invalid port spec 0x%x in ioctl",
* Get dev_info_t pointer to the device node pointed to by port argument. * NOTE: target argument is a value used in ioctls to identify * the AP - it is not a sata_address. * It is a combination of cport, pmport and address qualifier, encodded same * way as a scsi target number. * At this moment it carries only cport number. * No PMult hotplug support. * Returns dev_info_t pointer if target device was found, NULL otherwise. * This is actually an error condition, but not * a fatal one. Just continue the search. * Get dev_info_t pointer to the device node pointed to by port argument. * NOTE: target argument is a value used in ioctls to identify * the AP - it is not a sata_address. * It is a combination of cport, pmport and address qualifier, encoded same * way as a scsi target number. * At this moment it carries only cport number. * No PMult hotplug support. * Returns dev_info_t pointer if target device was found, NULL otherwise. * This is actually an error condition, but not * a fatal one. Just continue the search. * Process sata port disconnect request. * Normally, cfgadm sata plugin will try to offline (unconfigure) the device * before this request. Nevertheless, if a device is still configured, * we need to attempt to offline and unconfigure device. * Regardless of the unconfigure operation results the port is marked as * deactivated and no access to the attached device is possible. * If the target node remains because unconfigure operation failed, its state * will be set to DEVICE_REMOVED, preventing it to be used again when a device * the device and remove old target node. * This function invokes sata_hba_inst->satahba_tran-> * sata_tran_hotplug_ops->sata_tran_port_deactivate(). * If successful, the device structure (if any) attached to the specified port * is removed and state of the port marked appropriately. * Failure of the port_deactivate may keep port in the physically active state, * NOTE: Port multiplier code is not completed nor tested. * DEVCTL_AP_DISCONNECT invokes sata_hba_inst->satahba_tran-> * sata_tran_hotplug_ops->sata_tran_port_deactivate(). /* No physical port deactivation supported. */ /* Check the current state of the port */ /* Device port status is unknown or it is in failed state */ "sata_hba_ioctl: connect: failed to deactivate " "sata_hba_ioctl: connect: failed to deactivate " * Set port's dev_state to not ready - this will disable * an access to a potentially attached device. * If a target node exists, try to offline * a device and remove target node. /* We are addressing attached device, not a port */ * The target node remained attached. * This happens when the device file was open * or a node was waiting for resources. * Cannot do anything about it. "sata_hba_ioctl: disconnect: could " "not unconfigure device before " "disconnecting the SATA port %d",
"sata_hba_ioctl: disconnect: could " "not unconfigure device before " "disconnecting the SATA port %d:%d",
* Set DEVICE REMOVED state in the target * node. It will prevent access to the device * even when a new device is attached, until * the old target node is released, removed and * recreated for a new device. * Instruct event daemon to try the target /* Remove and release sata_drive info structure. */ * Port Multiplier itself needs special handling. * All device ports need to be processed here! /* Just ask HBA driver to deactivate port */ /* sata_device->satadev_addr.qual = SATA_ADDR_DCPORT; */ * Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE * without the hint (to force listener to investivate the state). * Port deactivation failure - do not * change port state unless the state * returned by HBA indicates a port failure. * NOTE: device structures were released, so devices now are * invisible! Port reset is needed to re-enumerate devices. * Deactivation succeded. From now on the sata framework * will not care what is happening to the device, until * the port is activated again. * Process sata port connect request * The sata cfgadm pluging will invoke this operation only if port was found * in the disconnect state (failed state is also treated as the disconnected * DEVCTL_AP_CONNECT would invoke sata_hba_inst->satahba_tran-> * sata_tran_hotplug_ops->sata_tran_port_activate(). * If successful and a device is found attached to the port, * the initialization sequence is executed to attach a device structure to * a port structure. The state of the port and a device would be set * The device is not set in configured state (system-wise) by this operation. * Note, that activating the port may generate link events, * so it is important that following processing and the * event processing does not interfere with each other! * This operation may remove port failed state and will * try to make port active and in good standing. * NOTE: Port multiplier code is not completed nor tested. * DEVCTL_AP_CONNECT would invoke sata_hba_inst-> * satahba_tran->sata_tran_hotplug_ops->sata_tran_port_activate(). * Perform sanity check now. /* No physical port activation supported. */ /* Just ask HBA driver to activate port */ * Port activation failure. "sata_hba_ioctl: connect: failed to " "activate SATA port %d",
cport);
}
else {
/* port multiplier device port */ "sata_hba_ioctl: connect: failed to " "sata_hba_ioctl: connect: failed to activate SATA " /* Virgin port state - will be updated by the port re-probe. */ else /* port multiplier device port */ * Probe the port to find its state and attached device. * Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE * If there is a device attached to the port, emit "SATA device detected at port %d",
cport);
* A device was not successfully identified "Could not identify SATA " "device at port %d",
cport);
}
else {
/* port multiplier device port */ "SATA device detected at port %d:%d",
* A device was not successfully identified "Could not identify SATA " * Process sata device unconfigure request. * The unconfigure operation uses generic nexus operation to * offline a device. It leaves a target device node attached. * and obviously sata_drive_info attached as well, because * from the hardware point of view nothing has changed. /* We are addressing attached device, not a port */ "sata_hba_ioctl: unconfigure: " "failed to unconfigure device at SATA port %d:%d",
* The target node devi_state should be marked with * DEVI_DEVICE_OFFLINE by ndi_devi_offline(). * This would be the indication for cfgadm that * the AP node occupant state is 'unconfigured'. * This would indicate a failure on the part of cfgadm * to detect correct state of the node prior to this * call - one cannot unconfigure non-existing device. "sata_hba_ioctl: unconfigure: " "attempt to unconfigure non-existing device " * Process sata device configure request * If port is in a failed state, operation is aborted - one has to use * an explicit connect or port activate request to try to get a port into * non-failed mode. Port reset wil also work in such situation. * If the port is in disconnected (shutdown) state, the connect operation is * attempted prior to any other action. * When port is in the active state, there is a device attached and the target * node exists, a device was most likely offlined. * If target node does not exist, a new target node is created. In both cases * an attempt is made to online (configure) the device. * NOTE: Port multiplier code is not completed nor tested. /* Get current port state */ * Obviously, device on a failed port is not visible /* need to activate port */ /* Just let HBA driver to activate port */ * Port activation failure - do not change port state * unless the state returned by HBA indicates a port "sata_hba_ioctl: configure: " "failed to activate SATA port %d:%d",
* Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE * Always reprobe port, to get current device info. * That's the transition from "inactive" port * to active one with device attached. "SATA device detected at port %d:%d",
* When PM is attached to the cport and cport is * activated, every PM device port needs to be reprobed. * We need to emit message for all devices detected * at port multiplier's device ports. * For now, just inform about device attached to "SATA device detected at port %d",
cport);
* This is where real configuration operation starts. * When PM is attached to the cport and cport is activated, * devices attached PM device ports may have to be configured * explicitly. This may change when port multiplier is supported. * For now, configure only disks and other valid target devices. * A device was not successfully identified "Could not identify SATA " "device at port %d",
cport);
}
else {
/* port multiplier device port */ * A device was not successfully identified "Could not identify SATA " return (
ENXIO);
/* No device to configure */ * Here we may have a device in reset condition, * but because we are just configuring it, there is * no need to process the reset other than just * to clear device reset condition in the HBA driver. * Setting the flag SATA_EVNT_CLEAR_DEVICE_RESET will * cause a first command sent the HBA driver with the request * to clear device reset condition. * Target node exists. Verify, that it belongs * to existing, attached device and not to "SATA device at port %d cannot be " "Application(s) accessing " "previously attached device " "have to release it before newly " "inserted device can be made accessible.",
"SATA device at port %d:%d cannot be" "Application(s) accessing " "previously attached device " "have to release it before newly " "inserted device can be made accessible.",
* Device was not removed and re-inserted. "sata_hba_ioctl: configure: " "onlining device at SATA port " * No target node - need to create a new target node. /* Configure operation failed */ "sata_hba_ioctl: configure: " "configuring SATA device at port %d:%d " * Process ioctl deactivate port request. * Arbitrarily unconfigure attached device, if any. * Even if the unconfigure fails, proceed with the * NOTE: Port Multiplier code is not completed and tested. * For now, assume that port multiplier is not * supported, i.e. deal only with valid devices * If attached device is a port multiplier, we will * have to unconfigure all devices attached to the * port multiplier. Add this code here. /* Port multiplier device port */ * If a target node exists, try to offline a device and * to remove a target node. "sata_hba_ioctl: port deactivate: " "target node exists.",
NULL);
"sata_hba_ioctl: port deactivate: " "failed to unconfigure device at port " "%d:%d before deactivating the port",
* Set DEVICE REMOVED state in the target * node. It will prevent an access to * the device even when a new device is * attached, until the old target node is * released, removed and recreated for a new * Instruct the event daemon to try the * target node cleanup later. * In any case, remove and release sata_drive_info }
else {
/* port multiplier device port */ }
else {
/* port multiplier device port */ /* Just let HBA driver to deactivate port */ * Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE * Port deactivation failure - do not change port state * unless the state returned by HBA indicates a port "sata_hba_ioctl: port deactivate: " "cannot deactivate SATA port %d",
cport));
"sata_hba_ioctl: port deactivate: " "cannot deactivate SATA port %d:%d",
* Process ioctl port activate request. * NOTE: Port multiplier code is not completed nor tested. /* Just let HBA driver to activate port, if necessary */ * Port activation failure - do not change port state unless * the state returned by HBA indicates a port failure. "sata_hba_ioctl: port activate: cannot activate " * Re-probe port to find its current state and possibly attached device. * Port re-probing may change the cportinfo device type if device is * If port probing failed, the device type would be set to * Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE * That's the transition from the "inactive" port state * or the active port without a device attached to the * active port state with a device attached. "SATA device detected at port %d:%d",
* That's the transition from the "inactive" port state * or the active port without a device attached to the * active port state with a device attached. "SATA device detected at port %d",
cport);
"SATA port multiplier detected at port %d",
* Because the detected device is a port * multiplier, we need to reprobe every device * port on the port multiplier and show every * Process ioctl reset port request. * NOTE: Port multiplier code is not completed nor tested. "sata_hba_ioctl: sata_hba_tran missing required " "function sata_tran_reset_dport"));
/* Ask HBA to reset port */ "sata_hba_ioctl: reset port: failed %d:%d",
* Beacuse the port was reset, it should be probed and * attached device reinitialized. At this point the * port state is unknown - it's state is HBA-specific. * Re-probe port to get its state. * Process ioctl reset device request. * NOTE: Port multiplier code is not completed nor tested. "sata_hba_ioctl: sata_hba_tran missing required " "function sata_tran_reset_dport"));
}
else {
/* port multiplier */ /* Ask HBA to reset device */ "sata_hba_ioctl: reset device: failed at port %d:%d",
* Device info structure remains attached. Another device reset * needed to change it's state * If attached device was a port multiplier, some extra processing * may be needed, to bring it back (if port re-probing did not handle * it). Add such code here. * Process ioctl reset all request. * NOTE: Port multiplier code is not completed nor tested. * There is no protection here for configured devices. "sata_hba_ioctl: sata_hba_tran missing required " "function sata_tran_reset_dport"));
* Need to lock all ports, not just one. * If any port is locked by event processing, fail the whole operation. * One port is already locked, but for simplicity lock it again. * If there is a port multiplier attached, we may need * to lock its port as well. If so, add such code here. * All cports were successfully locked. * Reset main SATA controller only for now - no PMult. * Set the device address to port 0, to have a valid device "sata_hba_ioctl: reset controller failed"));
* Because ports were reset, port states are unknown. * They should be re-probed to get their state and * attached devices should be reinitialized. * Add code here to re-probe port multiplier device ports. * This operation returns EFAULT if either reset * controller failed or a re-probing of any port failed. * Process ioctl port self test request. * NOTE: Port multiplier code is not completed nor tested. * There is no protection here for a configured * device attached to this port. "sata_hba_ioctl: port selftest: " else /* port ultiplier device port */ * Beacuse the port was reset in the course of testing, it should be * re-probed and attached device state should be restored. At this * point the port state is unknown - it's state is HBA-specific. * Force port re-probing to get it into a known state. * Use the sata port state and state of the target node to figure out * The port argument is a value with encoded cport, * pmport and address qualifier, in the same manner as a scsi target number. * SCSI_TO_SATA_CPORT macro extracts cport number, * SCSI_TO_SATA_PMPORT extracts pmport number and * SCSI_TO_SATA_ADDR_QUAL extracts port mulitplier qualifier flag. * For now, support is for cports only - no port multiplier device ports. /* Need to check pmult device port here as well, when supported */ /* Port is enabled and ready */ * There could be the case where previously * configured and opened device was removed * and unknown device was plugged. * In such case we want to show a device, and * its configured or unconfigured state but * indicate unusable condition untill the * old target node is released and removed. * This is actually internal error condition (non fatal), * because we have already checked all defined device types. "sata_cfgadm_state: Internal error: " * Process ioctl get device path request. * NOTE: Port multiplier code is not completed nor tested. * No such device. If this is a request for a size, do not * return EINVAL for non-existing target, because cfgadm * will then indicate a meaningless ioctl failure. * If this is a request for a path, indicate invalid * Process ioctl get attachment point type request. * NOTE: Port multiplier code is not completed nor tested. }
/* end of dev_type switch */ * Process ioctl get device model info request. * This operation should return to cfgadm the device model * NOTE: Port multiplier code is not completed nor tested. else /* port multiplier */ #
else /* _LITTLE_ENDIAN */#
endif /* _LITTLE_ENDIAN */ * Process ioctl get device firmware revision info request. * This operation should return to cfgadm the device firmware revision * NOTE: Port multiplier code is not completed nor tested. else /* port multiplier */ #
else /* _LITTLE_ENDIAN */#
endif /* _LITTLE_ENDIAN */ * Process ioctl get device serial number info request. * This operation should return to cfgadm the device serial number string. * NOTE: Port multiplier code is not completed nor tested. else /* port multiplier */ #
else /* _LITTLE_ENDIAN */#
endif /* _LITTLE_ENDIAN */ * Preset scsi extended sense data (to NO SENSE) * First 18 bytes of the sense data are preset to current valid sense * with a key NO SENSE data. * Register a legacy cmdk-style devid for the target (disk) device. * Note: This function is called only when the HBA devinfo node has the * property "use-cmdk-devid-format" set. This property indicates that * devid compatible with old cmdk (target) driver is to be generated * for any target device attached to this controller. This will take * precedence over the devid generated by sd (target) driver. * This function is derived from cmdk_devid_setup() function in cmdk.c. * device ID is a concatanation of model number, "=", serial number. * valid model/serial string must contain a non-zero non-space characters. if (
ch !=
' ' &&
ch !=
'\0')
if (
ch !=
' ' &&
ch !=
'\0' &&
ch !=
'0')
return (0);
/* invalid string */ return (
tb);
/* return length */ * sata_set_drive_features function compares current device features setting * with the saved device features settings and, if there is a difference, * it restores device features setting to the previously saved state. * It also arbitrarily tries to select the highest supported DMA mode. * Device Identify or Identify Packet Device data has to be current. * At the moment read ahead and write cache are considered for all devices. * For atapi devices, Removable Media Status Notification is set in addition * This function cannot be called in the interrupt context (it may sleep). * The input argument sdinfo should point to the drive info structure * to be updated after features are set. Note, that only * device (packet) identify data is updated, not the flags indicating the * Returns SATA_SUCCESS if successful or there was nothing to do. * Device Identify data in the drive info structure pointed to by the sdinfo * arguments is updated even when no features were set or changed. * Returns SATA_FAILURE if device features could not be set or DMA mode * for a disk cannot be set and device identify data cannot be fetched. * Returns SATA_RETRY if device features could not be set (other than disk * DMA mode) but the device identify data was fetched successfully. * Note: This function may fail the port, making it inaccessible. * detach/attach is required to re-evaluate port state again. char *
finfo =
"sata_set_drive_features: cannot";
* Cannot get device identification - caller may retry later "%s fetch device identify data\n",
finfo);
" initialize device features\n";
/* Arbitrarily set UDMA mode */ "%s set UDMA mode\n",
finfo));
/* Set Removable Media Status Notification, if necessary */ /* Current setting does not match saved one */ * We have to set Multiword DMA or UDMA, if it is supported, as * we want to use DMA transfer mode whenever possible. * Some devices require explicit setting of the DMA mode. /* Set highest supported DMA mode */ "%s set UDMA mode\n",
finfo));
/* None of the features is supported - do nothing */ "settable features not supported\n",
NULL);
"no device features to set\n",
NULL);
/* Enable read ahead / read cache */ "enabling read cache\n",
NULL);
/* Disable read ahead / read cache */ "disabling read cache\n",
NULL);
/* Try to set read cache mode */ "enabling write cache\n",
NULL);
/* Disable write cache */ "disabling write cache\n",
NULL);
/* Try to set write cache mode */ * We need to fetch Device Identify data again * Cannot get device identification - retry later "%s re-fetch device identify data\n",
finfo));
/* Copy device sata info. */ * Returns 1 if threshold exceeded, 0 if threshold not exceeded, -1 if * Cannot be called in an interrupt context. * Called by sata_build_lsense_page_2f() /* address is needed now */ /* Synchronous mode, no callback */ /* Set up which registers need to be returned */ /* Build SMART_RETURN_STATUS cmd in the sata_pkt */ /* Send pkt to SATA HBA driver */ * Whoops, no SMART RETURN STATUS /* Free allocated resources */ * Returns 0 if succeeded, -1 otherwise * Cannot be called in an interrupt context. /* address is needed now */ /* Synchronous mode, no callback */ * Allocate buffer for SMART data "sata_fetch_smart_data: " "cannot allocate buffer"));
/* Build SMART_READ_DATA cmd in the sata_pkt */ /* Send pkt to SATA HBA driver */ * Whoops, no SMART DATA available /* Free allocated resources */ * Used by LOG SENSE page 0x10 * Reads (in synchronous mode) the self test log data using Read Log Ext cmd. * Note: cannot be called in the interrupt context. * return 0 for success, -1 otherwise /* address is needed now */ /* Synchronous mode, no callback */ * Allocate buffer for SMART extended self-test log "sata_ext_smart_selftest_log: " "cannot allocate buffer"));
/* Build READ LOG EXT w/ extended self-test log cmd in the sata_pkt */ /* Send pkt to SATA HBA driver */ * Whoops, no SMART selftest log info available /* Free allocated resources */ * Returns 0 for success, -1 otherwise * SMART self-test log data is returned in buffer pointed to by selftest_log /* address is needed now */ /* Synchronous mode, no callback */ * Allocate buffer for SMART SELFTEST LOG "sata_smart_selftest_log: " "cannot allocate buffer"));
/* Build SMART_READ_LOG cmd in the sata_pkt */ /* Send pkt to SATA HBA driver */ * Whoops, no SMART DATA available /* Free allocated resources */ * Returns 0 for success, -1 otherwise * SMART READ LOG data is returned in buffer pointed to by smart_log /* address is needed now */ /* Synchronous mode, no callback */ * Allocate buffer for SMART READ LOG "sata_smart_read_log: " "cannot allocate buffer"));
/* Build SMART_READ_LOG cmd in the sata_pkt */ /* Send pkt to SATA HBA driver */ * Whoops, no SMART DATA available /* Free allocated resources */ * Used by LOG SENSE page 0x10 * return 0 for success, -1 otherwise /* Synchronous mode, no callback */ * Allocate buffer for SMART READ LOG EXTENDED command "sata_read_log_ext_directory: " "cannot allocate buffer"));
/* Build READ LOG EXT w/ log directory cmd in the sata_pkt */ /* Send pkt to SATA HBA driver */ * Whoops, no SMART selftest log info available /* Free allocated resources */ * Set up error retrieval sata command for NCQ command error data * Returns SATA_SUCCESS when data buffer is allocated and packet set-up, * returns SATA_FAILURE otherwise. /* Operation modes are up to the caller */ /* Synchronous mode, no callback - may be changed by the caller */ * Allocate dma_able buffer error data. * Buffer allocation will take care of buffer alignment and other DMA * Set-up pointer to the buffer handle, so HBA can sync buffer * before accessing it. Handle is in usual place in translate struct. * sata_xlate_errors() is used to translate (S)ATA error * information to SCSI information returned in the SCSI * We have no device data. Assume no data transfered. * determine dev error reason from error /* No extended sense key - no info available */ /* No extended sense key */ /* No extended sense key */ * pkt aborted either by an explicit reset request from * a host, or due to error recovery * dev pathname msg line preceeds the logged message. /* ******** Asynchronous HBA events handling & hotplugging support ******** */ * Start or terminate the thread, depending on flag arg and current state /* wait til terminate operation completes */ "timeout waiting for thread to terminate");
* If we got here, thread may need to be terminated /* Signal event thread to go away */ * Wait til daemon terminates. /* Daemon did not go away !!! */ "cannot terminate event daemon thread");
* SATA HBA event notification function. * Events reported by SATA HBA drivers per HBA instance relate to a change in * a port and/or device state or a controller itself. * A warning message is generated for each event type. * Events are not processed by this function, so only the * event flag(s)is set for an affected entity and the event thread is * waken up. Event daemon thread processes all events. * NOTE: Since more than one event may be reported at the same time, one * cannot determine a sequence of events when opposite event are reported, eg. * LINK_LOST and LINK_ESTABLISHED. Actual port status during event processing * is taking precedence over reported events, i.e. may cause ignoring some "sata_hba_event_notify: invalid port event 0x%x ";
"sata_hba_event_notify: invalid device event 0x%x ";
* There is a possibility that an event will be generated on HBA * that has not completed attachment or is detaching. We still want * to process events until HBA is detached. * Validate address before - do not proceed with invalid address. /* Port Multiplier not supported yet */ * If event relates to port or device, check port state. * Port has to be initialized, or we cannot accept an event. * Events refer to devices, ports and controllers - each has * unique address. Events for different addresses cannot be combined. /* qualify this event(s) */ /* Invalid event for the device port */ /* Controller's device port event */ /* Port multiplier's device port event */ * Add to statistics and log the message. We have to do it * here rather than in the event daemon, because there may be * multiple events occuring before they are processed. /* This is likely event combination */ "port %d power level changed",
cport);
/* There should be no other events for this address */ /* Invalid event for a device */ /* Invalid event for a device */ /* Wrong address qualifier */ "sata_hba_event_notify: invalid address 0x%x",
/* Invalid event for the controller */ "sata_hba_event_notify: invalid event 0x%x for " /* This may be a frequent and not interesting event */ "controller power level changed\n",
NULL);
* If we got here, there is something to do with this HBA /* Tickle event thread */ * Event processing thread. * Arg is a pointer to the sata_hba_list pointer. * It is not really needed, because sata_hba_list is global and static "SATA event daemon started\n",
NULL);
* Process events here. Walk through all registered HBAs /* Got the controller with pending event */ * Since global mutex was released, there is a * possibility that HBA list has changed, so start * over from the top. Just processed controller * will be passed-over because of the SKIP flag. /* Clear SKIP flag in all controllers */ "SATA EVENT DAEMON suspending itself",
NULL);
"SATA EVENTS PROCESSING DISABLED\n");
* Go to sleep/suspend itself and wake up either because new event or * wait timeout. Exit if there is a termination request (driver /* Check if it is time to go away */ * It is up to the thread setting above flag to make * sure that this thread is not killed prematurely. "SATA_EVENT_DAEMON_TERMINATING",
NULL);
"SATA EVENT DAEMON READY TO PROCESS EVENT",
NULL);
* Specific HBA instance event processing. * NOTE: At the moment, device event processing is limited to hard disks * cports only are supported - no pmports. "Processing controller %d event(s)",
* Process controller power change first * We may have to process events for more than one port/device. * Not all ports may be processed in attach by the time we * get an event. Check if port info is initialized. /* We have initialized controller port info */ /* Check if port was locked by IOCTL processing */ * We ignore port events because port is busy * with AP control processing. Set again * controller and main event flag, so that * events may be processed by the next daemon "Event processing postponed until " "AP control processing completes",
* Set BSY flag so that AP control would not * interfere with events processing for * We need some hierarchy of event processing as they * are affecting each other: * 3. link events - link events may trigger device * detached or device attached events in some * 4. port power level changed /* Release PORT_BUSY flag */ }
/* End of loop through the controller SATA ports */ * Process HBA power level change reported by HBA driver. * Not implemented at this time - event is ignored. "Processing controller power level change",
NULL);
/* Ignoring it for now */ * Process port power level change reported by HBA driver. * Not implemented at this time - event is ignored. "Processing port power level change",
NULL);
* Process port failure reported by HBA driver. * cports support only - no pmports. /* Reset event flag first */ /* If the port is in SHUTDOWN or FAILED state, ignore this event. */ * Device Reset Event processing. * The seqeunce is managed by 3 stage flags: * - reset event reported, * - reset event being processed, * - request to clear device reset state. * NOTE: This function has to be entered with cport mutex held. It exits with * mutex held as well, but can release mutex during the processing. /* We only care about host sata cport for now */ * If the port is in SHUTDOWN or FAILED state, or device is in FAILED * state, ignore reset event. * This should not happen - coding error. * But we can recover, so do not panic, just clean up * and if in debug mode, log the message. "sata_process_device_reset: " "Invalid device type with sdinfo!",
NULL);
/* Something is weird - why we are processing dev reset? */ "No device reset event!!!!",
NULL);
/* Something is weird - new device reset event */ "Overlapping device reset events!",
NULL);
/* It seems that we always need to check the port state first */ * We have to exit mutex, because the HBA probe port function may * block on its own mutex. /* Something went wrong? Fail the port */ "SATA port %d probing failed",
* No device to process, anymore. Some other event processing * would or have already performed port info cleanup. * To be safe (HBA may need it), request clearing device * Start tracking time for device feature restoration and * identification. Save current time (lbolt value). /* Mark device reset processing as active */ * Restoring drive setting failed. * Probe the port first, to check if the port state has changed * We may retry this a bit later - in-process reset * condition should be already set. * Track retry time for device identification. * If the retry time limit was not * Setting drive features failed, but * the drive is still accessible, * so emit a warning message before "SATA device at port %d - device failed",
* No point of retrying - device failed or some other event * processing or already did or will do port info cleanup. * To be safe (HBA may need it), * request clearing device reset condition. * If setting of drive features failed, but the drive is still * accessible, emit a warning message. "SATA device at port %d - desired setting could not be " "restored after reset. Device may not operate as expected.",
* Raise the flag indicating that the next sata command could * be sent with SATA_CLEAR_DEV_RESET_STATE flag, if no new device * Port Link Events processing. * Every link established event may involve device reset (due to * COMRESET signal, equivalent of the hard reset) so arbitrarily * set device reset event for an attached device (if any). * If the port is in SHUTDOWN or FAILED state, ignore link events. * The link established event processing varies, depending on the state * of the target node, HBA hotplugging capabilities, state of the port. * If the link is not active, the link established event is ignored. * If HBA cannot detect device attachment and there is no target node, * the link established event triggers device attach event processing. * Else, link established event triggers device reset event processing. * The link lost event processing varies, depending on a HBA hotplugging * capability and the state of the port (link active or not active). * If the link is active, the lost link event is ignored. * If HBA cannot detect device removal, the lost link event triggers * device detached event processing after link lost timeout. * Else, the event is ignored. * NOTE: Only cports are processed for now, i.e. no port multiplier ports "Processing port %d link event(s)",
saddr->
cport);
/* Reset event flags first */ /* If the port is in SHUTDOWN or FAILED state, ignore link events. */ * For the sanity sake get current port state. * Set device address only. Other sata_device fields should be * We have to exit mutex, because the HBA probe port function may * block on its own mutex. /* Something went wrong? Fail the port */ "SATA port %d probing failed",
* We may want to release device info structure, but /* port probed successfully */ "Ignoring port %d link established event - " "Processing port %d link established event",
* For the sanity sake check if a device is attached - check * return state of a port probing. * HBA port probe indicated that there is a device * attached. Check if the framework had device info * structure attached for this device. * Dev info structure is present. * If dev_type is set to known type in * the framework's drive info struct * then the device existed before and * the link was probably lost * momentarily - in such case * we may want to check device * Identity check is not supported now. * triggers device reset event. * We got new device attached! If HBA does not * generate device attached events, trigger it /* Reset link lost timeout */ "Ignoring port %d link lost event - link is up",
"Processing port %d link lost event",
* we need to track link lost time and eventually generate /* We are tracking link lost time */ /* save current time (lbolt value) */ /* just keep link lost event */ /* trigger device detach event */ /* keep link lost event */ * the attached device until the link is recovered. * Device Detached Event processing. * Port is probed to find if a device is really gone. If so, * the device info structure is detached from the SATA port info structure * Port status is updated. * NOTE: Process cports event only, no port multiplier ports. "Processing port %d device detached",
saddr->
cport);
/* If the port is in SHUTDOWN or FAILED state, ignore detach event. */ /* For sanity, re-probe the port */ * We have to exit mutex, because the HBA probe port function may * block on its own mutex. /* Something went wrong? Fail the port */ "SATA port %d probing failed",
* We may want to release device info structure, but /* port probed successfully */ * Check if a device is still attached. For sanity, check also * link status - if no link, there is no device. * Device is still attached - ignore detach event. "Ignoring detach - device still attached to port %d",
* We need to detach and release device info structure here * Device cannot be reached anymore, even if the target node may be * Try to offline a device and remove target node if it still exists * Target node exists. Unconfigure device then remove * the target node (one ndi operation). * PROBLEM - no device, but target node remained * This happens when the file was open or node was "sata_process_device_detached: " "Failed to remove target node for " "detached SATA device."));
* Set target node state to DEVI_DEVICE_REMOVED. * But re-check first that the node still exists. * Instruct event daemon to retry the * Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE * with the hint: SE_HINT_REMOVE * Device Attached Event processing. * Port state is checked to verify that a device is really attached. If so, * the device info structure is created and attached to the SATA port info * If attached device cannot be identified or set-up, the retry for the * attach processing is set-up. Subsequent daemon run would try again to * identify the device, until the time limit is reached * (SATA_DEV_IDENTIFY_TIMEOUT). * This function cannot be called in interrupt context (it may sleep). * NOTE: Process cports event only, no port multiplier ports. "Processing port %d device attached",
saddr->
cport);
/* Clear attach event flag first */ /* If the port is in SHUTDOWN or FAILED state, ignore event. */ * If the sata_drive_info structure is found attached to the port info, * despite the fact the device was removed and now it is re-attached, * the old drive info structure was not removed. * Arbitrarily release device info structure. "Arbitrarily detaching old device info.",
NULL);
/* For sanity, re-probe the port */ * We have to exit mutex, because the HBA probe port function may * block on its own mutex. /* Something went wrong? Fail the port */ "SATA port %d probing failed",
/* port probed successfully */ * Check if a device is still attached. For sanity, check also * link status - if no link, there is no device. * No device - ignore attach event. "Ignoring attach - no device connected to port %d",
* Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE * with the hint: SE_HINT_INSERT * Port reprobing will take care of the creation of the device * info structure and determination of the device type. /* Some device is attached to the port */ * A device was not successfully attached. * Track retry time for device identification. * If the retry time limit was not exceeded, * reinstate attach event. /* OK, restore attach event */ /* Timeout - cannot identify device */ "Could not identify SATA device " * Start tracking time for device * Save current time (lbolt value). /* Restore attach event */ * If device was successfully attached, the subsequent * action depends on a state of the * sata_auto_online variable. If it is set to zero. * an explicit 'configure' command will be needed to * configure it. If its value is non-zero, we will * attempt to online (configure) the device. * First, log the message indicating that a device /* Log device info data */ * Make sure that there is no target node for that * device. If so, release it. It should not happen, * unless we had problem removing the node when "sata_process_device_attached: " "old device target node exists!");
* target node exists - try to unconfigure * device and remove the node. * PROBLEM - the target node remained * and it belongs to a previously * This happens when the file was open * or the node was waiting for * resources at the time the * associated device was removed. * Instruct event daemon to retry the "Application(s) accessing " "previously attached SATA " "device have to release " "it before newly inserted " "device can be made accessible.",
* Device Target Node Cleanup Event processing. * If the target node associated with a sata port device is in * DEVI_DEVICE_REMOVED state, an attempt is made to remove it. * If the target node cannot be removed, the event flag is left intact, * so that event daemon may re-run this function later. * This function cannot be called in interrupt context (it may sleep). * NOTE: Processes cport events only, not port multiplier ports. "Processing port %d device target node cleanup",
saddr->
cport);
* Check if there is target node for that device and it is in the * DEVI_DEVICE_REMOVED state. If so, release it. * target node exists - check if it is target node of "sata_process_target_node_cleanup: " "old device target node exists!",
NULL);
* Unconfigure and remove the target node * Event daemon will retry the cleanup later. * Device AutoOnline Event processing. * If attached device is to be onlined, an attempt is made to online this * device, but only if there is no lingering (old) target node present. * If the device cannot be onlined, the event flag is left intact, * so that event daemon may re-run this function later. * This function cannot be called in interrupt context (it may sleep). * NOTE: Processes cport events only, not port multiplier ports. "Processing port %d attached device auto-onlining",
saddr->
cport);
* Check if device is present and recognized. If not, reset event. * Check if there is target node for this device and if it is in the * DEVI_DEVICE_REMOVED state. If so, abort onlining but keep * the event for later processing. * target node exists - check if it is target node of "sata_process_device_autoonline: " "old device target node exists!",
NULL);
* Event daemon will retry device onlining later. * If the target node is not in the 'removed" state, assume * that it belongs to this device. There is nothing more to do, * Try to online the device * If there is any reset-related event, remove it. We are * configuring the device and no state restoring is needed. /* Need to create a new target node. */ * Configure (onlining) failed. "sata_process_device_autoonline: " "configuring SATA device at port %d failed",
/* Allocate and build sysevent attribute list */ "cannot allocate memory for sysevent attributes\n"));
"failed to add DR_HINT attr for sysevent"));
* Get controller pathname and convert it into AP pathname by adding "failed to add DR_AP_ID attr for sysevent"));
"cannot log sysevent, err code %x\n",
err));
* Set DEVI_DEVICE_REMOVED state in the SATA device target node. * Set internal event instructing event daemon to try * to perform the target node cleanup. * Check if the SATA device target node is in DEVI_DEVICE_REMOVED state, * i.e. check if the target node state indicates that it belongs to a removed * Returns B_TRUE if the target node is in DEVI_DEVICE_REMOVED state, * NOTE: No port multiplier support. /* ************************ FAULT INJECTTION **************************** */ * It modifies returned values of the sata packet. * It returns immediately if: * pkt fault injection is not enabled (via sata_inject_fault, * sata_inject_fault_count), or invalid fault is specified (sata_fault_type), * or pkt does not contain command to be faulted (set in sata_fault_cmd), or * (sata_fault_ctrl_dev and sata_fault_device). * If fault controller is not specified, fault injection applies to all * controllers and devices. * First argument is the pointer to the executed sata packet. * Second argument is a pointer to a value returned by the HBA tran_start * Third argument specifies injected error. Injected sata packet faults * are the satapkt_reason values. * SATA_PKT_BUSY -1 Not completed, busy * SATA_PKT_DEV_ERROR 1 Device reported error * SATA_PKT_QUEUE_FULL 2 Not accepted, queue full * SATA_PKT_PORT_ERROR 3 Not completed, port error * SATA_PKT_CMD_UNSUPPORTED 4 Cmd unsupported * SATA_PKT_ABORTED 5 Aborted by request * SATA_PKT_TIMEOUT 6 Operation timeut * SATA_PKT_RESET 7 Aborted by reset request * Additional global variables affecting the execution: * sata_inject_fault_count variable specifies number of times in row the * error is injected. Value of -1 specifies permanent fault, ie. every time * the fault injection point is reached, the fault is injected and a pause * between fault injection specified by sata_inject_fault_pause_count is * ignored). Fault injection routine decrements sata_inject_fault_count * (if greater than zero) until it reaches 0. No fault is injected when * sata_inject_fault_count is 0 (zero). * sata_inject_fault_pause_count variable specifies number of times a fault * injection is bypassed (pause between fault injections). * If set to 0, a fault is injected only a number of times specified by * sata_inject_fault_count. * The fault counts are static, so for periodic errors they have to be manually * reset to start repetition sequence from scratch. * If the original value returned by the HBA tran_start function is not * SATA_TRAN_ACCEPTED and pkt reason is not SATA_PKT_COMPLETED, no error * is injected (to avoid masking real problems); * NOTE: In its current incarnation, this function should be invoked only for * commands executed in SYNCHRONOUS mode. /* Modify pkt return parameters */ /* Pause in the injection */ * Init inject fault cycle. If fault count is set to -1, * it is a permanent fault. /* This is "rejected" command */ /* Additional error setup could be done here - port state */ * Additional error setup could be done here /* Additional error setup could be done here */ * Additional error setup could be done here - device reset